mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 02:49:02 -04:00
Remove the requirement to snapshot content files
The new content file format now includes metadata for previous versions of files. This allows the fix command to access historical file data from snapshots as needed, ensuring recovery even if the live filesystem has changed or the file was deleted during a sync.
This commit is contained in:
parent
69d467e9ef
commit
20cdfa7535
13 changed files with 209 additions and 368 deletions
20
HISTORY
20
HISTORY
|
|
@ -6,18 +6,14 @@ SnapRAID HISTORY
|
|||
* Added support for automated filesystem snapshots to ensure data
|
||||
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 read-only 'stable' state upon
|
||||
successful completion (currently supported on Btrfs).
|
||||
This ensures that 'scrub', 'check', and 'fix' operations can use a
|
||||
frozen point-in-time reference for data disks, eliminating mismatches
|
||||
caused by concurrent live filesystem changes.
|
||||
The implementation includes a "time-capsule" feature that reflinks
|
||||
the .content file into the snapshot area, preserving the
|
||||
metadata-to-parity correlation even if files are later deleted from
|
||||
the live disk. During targeted 'check' or 'fix' operations, SnapRAID
|
||||
intelligently mixes live access for the disks being repaired with
|
||||
snapshot access for reference disks to maintain mathematical
|
||||
integrity across the array.
|
||||
of a sync and promotes it to a 'stable' state upon successful
|
||||
completion (currently supported on Btrfs).
|
||||
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.
|
||||
The use of snapshots significantly improves recovery success by
|
||||
preserving access to files that were updated or deleted after the
|
||||
last parity computation.
|
||||
* Implemented AVX-512BW (Byte and Word) support for parity generation
|
||||
and data recovery, optimizing performance on modern architectures
|
||||
like Intel Sapphire Rapids and AMD Zen 4/5.
|
||||
|
|
|
|||
|
|
@ -1047,7 +1047,7 @@ int state_device(struct snapraid_state* state, int operation, tommy_list* filter
|
|||
|
||||
entry = calloc_nofail(1, sizeof(devinfo_t));
|
||||
|
||||
entry->device = disk->device;
|
||||
entry->device = disk->mount_device;
|
||||
device_name_set(entry, disk->name, 0);
|
||||
pathcpy(entry->mount, sizeof(entry->mount), disk->dir);
|
||||
pathcpy(entry->smartctl, sizeof(entry->smartctl), disk->smartctl);
|
||||
|
|
|
|||
|
|
@ -824,7 +824,8 @@ struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev
|
|||
disk->smartignore[i] = 0;
|
||||
disk->fstype[0] = 0;
|
||||
disk->fslabel[0] = 0;
|
||||
disk->device = dev;
|
||||
disk->mount_device = dev;
|
||||
disk->dir_device = dev;
|
||||
disk->tick = 0;
|
||||
disk->cached_blocks = 0;
|
||||
disk->progress_file = 0;
|
||||
|
|
|
|||
|
|
@ -390,7 +390,8 @@ struct snapraid_disk {
|
|||
char fstype[FSINFO_MAX]; /**< Filesystem type */
|
||||
char fslabel[FSINFO_MAX]; /**< Filesystem label */
|
||||
|
||||
uint64_t device; /**< Device identifier. */
|
||||
uint64_t mount_device; /**< Device identifier of the mount_point. */
|
||||
uint64_t dir_device; /**< Device identifier of the effective dir. */
|
||||
block_off_t total_blocks; /**< Number of total blocks. */
|
||||
block_off_t free_blocks; /**< Number of free blocks at the last sync. */
|
||||
|
||||
|
|
|
|||
|
|
@ -2078,13 +2078,6 @@ int fssnapshot_create(const char* source, const char* parent_dir, const char* na
|
|||
return -1;
|
||||
}
|
||||
|
||||
int fssnapshot_readonly(const char* parent_dir, const char* name)
|
||||
{
|
||||
(void)parent_dir;
|
||||
(void)name;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fssnapshot_delete(const char* parent_dir, const char* name)
|
||||
{
|
||||
(void)parent_dir;
|
||||
|
|
@ -2100,14 +2093,6 @@ int fssnapshot_rename(const char* parent_dir, const char* old_name, const char*
|
|||
return -1;
|
||||
}
|
||||
|
||||
int fssnapshot_clone(const char* source, const char* dest)
|
||||
{
|
||||
(void)source;
|
||||
(void)dest;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* ensure to call the real C strerror() */
|
||||
#undef strerror
|
||||
|
||||
|
|
|
|||
|
|
@ -378,15 +378,6 @@ int fssnapshot(const char* path, char* root, size_t root_size);
|
|||
*/
|
||||
int fssnapshot_create(const char* source, const char* parent_dir, const char* name);
|
||||
|
||||
|
||||
/**
|
||||
* Make a snapshot read-only
|
||||
* @param parent_dir Directory where the snapshot is.
|
||||
* @param name Name of snapshot.
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
int fssnapshot_readonly(const char* parent_dir, const char* name);
|
||||
|
||||
/**
|
||||
* Deletes a subvolume/snapshot.
|
||||
* @param parent_dir Directory where the snapshot is.
|
||||
|
|
@ -401,13 +392,7 @@ int fssnapshot_delete(const char* parent_dir, const char* name);
|
|||
*/
|
||||
int fssnapshot_rename(const char* parent_dir, const char* old_name, const char* new_name);
|
||||
|
||||
/**
|
||||
* Clone a file between snapshots
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
int fssnapshot_clone(const char* source, const char* dest);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Log file.
|
||||
*
|
||||
* This stream if fully buffered.
|
||||
|
|
|
|||
|
|
@ -1601,7 +1601,7 @@ static int scan_sub(struct snapraid_scan* scan, int level, int is_diff, char* pa
|
|||
* In Unix don't follow mount points in different devices
|
||||
* in Windows we are already skipping them reporting them as special files
|
||||
*/
|
||||
if ((uint64_t)st->st_dev != disk->device) {
|
||||
if ((uint64_t)st->st_dev != disk->dir_device) {
|
||||
log_tag("%s:%u:%s:%s: Ignoring mount point.\n", es(ESOFT), 0, disk->name, esc_tag(path_next));
|
||||
log_error(ESOFT, "WARNING! Ignoring mount point '%s' because it appears to be in a different device\n", path_next);
|
||||
} else
|
||||
|
|
|
|||
135
cmdline/state.c
135
cmdline/state.c
|
|
@ -272,7 +272,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
|
|||
continue;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (disk->device == 0) {
|
||||
if (disk->dir_device == 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal(ESOFT, "Disk '%s' has a zero serial number.\n", disk->dir);
|
||||
log_fatal(ESOFT, "This is not necessarily wrong, but for using SnapRAID\n");
|
||||
|
|
@ -285,7 +285,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
|
|||
|
||||
for (j = i->next; j != 0; j = j->next) {
|
||||
struct snapraid_disk* other = j->data;
|
||||
if (disk->device == other->device) {
|
||||
if (disk->mount_device == other->mount_device) {
|
||||
if (state->opt.force_device) {
|
||||
/*
|
||||
* Note that we just ignore the issue
|
||||
|
|
@ -298,7 +298,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
|
|||
/* LCOV_EXCL_START */
|
||||
log_fatal(ESOFT, "Disks '%s' and '%s' are on the same device.\n", disk->mount_point, other->mount_point);
|
||||
#ifdef _WIN32
|
||||
log_fatal(ESOFT, "Both have the serial number '%" PRIx64 "'.\n", disk->device);
|
||||
log_fatal(ESOFT, "Both have the serial number '%" PRIx64 "'.\n", disk->dir_device);
|
||||
log_fatal(ESOFT, "Try using the 'VolumeID' tool by 'Mark Russinovich'\n");
|
||||
log_fatal(ESOFT, "to change one of the disk serial.\n");
|
||||
#endif
|
||||
|
|
@ -317,7 +317,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
|
|||
if (!state->opt.skip_parity_access) {
|
||||
for (l = 0; l < state->level; ++l) {
|
||||
for (s = 0; s < state->parity[l].split_mac; ++s) {
|
||||
if (disk->device == state->parity[l].split_map[s].device) {
|
||||
if (disk->mount_device == state->parity[l].split_map[s].device) {
|
||||
if (state->opt.force_device) {
|
||||
/*
|
||||
* Note that we just ignore the issue
|
||||
|
|
@ -330,7 +330,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
|
|||
/* LCOV_EXCL_START */
|
||||
log_fatal(ESOFT, "Disk '%s' and %s '%s' are on the same device.\n", disk->mount_point, lev_name(l), state->parity[l].split_map[s].path);
|
||||
#ifdef _WIN32
|
||||
log_fatal(ESOFT, "Both have the serial number '%" PRIx64 "'.\n", disk->device);
|
||||
log_fatal(ESOFT, "Both have the serial number '%" PRIx64 "'.\n", disk->dir_device);
|
||||
log_fatal(ESOFT, "Try using the 'VolumeID' tool by 'Mark Russinovich'\n");
|
||||
log_fatal(ESOFT, "to change one of the disk serial.\n");
|
||||
#endif
|
||||
|
|
@ -342,11 +342,11 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
|
|||
}
|
||||
}
|
||||
|
||||
if (state->pool[0] != 0 && disk->device == state->pool_device) {
|
||||
if (state->pool[0] != 0 && disk->mount_device == state->pool_device) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal(ESOFT, "Disk '%s' and pool '%s' are on the same device.\n", disk->mount_point, state->pool);
|
||||
#ifdef _WIN32
|
||||
log_fatal(ESOFT, "Both have the serial number '%" PRIx64 "'.\n", disk->device);
|
||||
log_fatal(ESOFT, "Both have the serial number '%" PRIx64 "'.\n", disk->dir_device);
|
||||
log_fatal(ESOFT, "Try using the 'VolumeID' tool by 'Mark Russinovich'\n");
|
||||
log_fatal(ESOFT, "to change one of the disk serial.\n");
|
||||
#endif
|
||||
|
|
@ -4559,7 +4559,7 @@ void state_read(struct snapraid_state* state)
|
|||
}
|
||||
|
||||
if (state->unsynced_blocks)
|
||||
msg_progress("The latest sync was interrupted!\n");
|
||||
msg_progress("WARNING! The latest sync was interrupted!\n");
|
||||
|
||||
/* update the mapping */
|
||||
state_map(state);
|
||||
|
|
@ -5814,6 +5814,24 @@ void state_load_ignore_file(tommy_list* filter_list, const char* path, const cha
|
|||
#define SNAPSHOT_PENDING "pending"
|
||||
#define SNAPSHOT_STABLE "stable"
|
||||
|
||||
static int state_snapshot_dir(const char* dir, struct snapraid_disk* disk)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (lstat(dir, &st) != 0)
|
||||
return -1;
|
||||
|
||||
if (!S_ISDIR(st.st_mode))
|
||||
return -1;
|
||||
|
||||
if (disk) {
|
||||
pathcpy(disk->dir, sizeof(disk->dir), dir);
|
||||
disk->dir_device = st.st_dev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int state_snapshot_new(struct snapraid_state* state)
|
||||
{
|
||||
if (!state->snapshot)
|
||||
|
|
@ -5823,6 +5841,7 @@ int state_snapshot_new(struct snapraid_state* state)
|
|||
struct snapraid_disk* disk = i->data;
|
||||
char root[PATH_MAX];
|
||||
char container[PATH_MAX];
|
||||
char vol[PATH_MAX];
|
||||
int ret;
|
||||
|
||||
/* check if it supports snapshot */
|
||||
|
|
@ -5843,22 +5862,27 @@ int state_snapshot_new(struct snapraid_state* state)
|
|||
|
||||
/* delete a potential previous pending snapshot */
|
||||
if (fssnapshot_delete(container, SNAPSHOT_PENDING) != 0) {
|
||||
log_fatal(errno, "Failed to delete pending snapshot in '%s' \n", container);
|
||||
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) {
|
||||
log_fatal(errno, "Failed to create pending snapshot '%s'\n", container);
|
||||
log_fatal(errno, "Failed to create pending snapshot '%s'. %s.\n", container, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg_progress("Created disk %s pending snapshot...\n", disk->name);
|
||||
|
||||
/* setup the snapshot in use */
|
||||
pathcpy(disk->dir, sizeof(disk->dir), container);
|
||||
pathcat(disk->dir, sizeof(disk->dir), "/" SNAPSHOT_PENDING "/");
|
||||
pathcat(disk->dir, sizeof(disk->dir), disk->mount_point + root_len);
|
||||
pathcpy(vol, sizeof(vol), container);
|
||||
pathcat(vol, sizeof(vol), "/" SNAPSHOT_PENDING "/");
|
||||
pathcat(vol, sizeof(vol), disk->mount_point + root_len);
|
||||
|
||||
if (state_snapshot_dir(vol, disk) != 0) {
|
||||
log_error(errno, "Error stating snapshot dir '%s'. %s.\n", vol, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* store the snapshot root */
|
||||
pathcpy(disk->snapshot_root, sizeof(disk->snapshot_root), root);
|
||||
|
|
@ -5880,45 +5904,18 @@ int state_snapshot_commit(struct snapraid_state* state)
|
|||
if (disk->snapshot_root[0] == 0)
|
||||
continue;
|
||||
|
||||
size_t root_len = strlen(disk->snapshot_root);
|
||||
|
||||
pathcpy(container, sizeof(container), disk->snapshot_root);
|
||||
pathcat(container, sizeof(container), SNAPSHOT_CONTAINER);
|
||||
|
||||
/* for each content file */
|
||||
for (tommy_node* j = state->contentlist; j != 0; j = j->next) {
|
||||
struct snapraid_content* content = j->data;
|
||||
|
||||
/* check if the content file is in the subvolume */
|
||||
if (strncmp(content->content, disk->snapshot_root, root_len) == 0) {
|
||||
/* clone the just written content file into the snapshot */
|
||||
char clone[PATH_MAX];
|
||||
|
||||
pathcpy(clone, sizeof(clone), container);
|
||||
pathcat(clone, sizeof(clone), "/" SNAPSHOT_PENDING "/");
|
||||
pathcat(clone, sizeof(clone), content->content + root_len);
|
||||
|
||||
if (fssnapshot_clone(content->content, clone) != 0) {
|
||||
log_fatal(errno, "Failed to clone the content file '%s'\n", content->content);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fssnapshot_readonly(container, SNAPSHOT_PENDING) != 0) {
|
||||
log_fatal(errno, "Failed to make pending snapshot read-only in '%s'\n", container);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* delete a potential previous stable snapshot */
|
||||
if (fssnapshot_delete(container, SNAPSHOT_STABLE) != 0) {
|
||||
log_fatal(errno, "Failed to delete stable snapshot in '%s'\n", container);
|
||||
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) {
|
||||
log_fatal(errno, "Failed to rename snapshot in '%s'\n", container);
|
||||
log_fatal(errno, "Failed to rename snapshot in '%s'. %s.\n", container, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
@ -5928,16 +5925,6 @@ int state_snapshot_commit(struct snapraid_state* state)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int is_dir(const char* path)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (lstat(path, &st) != 0)
|
||||
return 0;
|
||||
|
||||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
|
||||
void state_snapshot_read(struct snapraid_state* state)
|
||||
{
|
||||
if (!state->snapshot)
|
||||
|
|
@ -5959,21 +5946,18 @@ void state_snapshot_read(struct snapraid_state* state)
|
|||
pathcat(container, sizeof(container), SNAPSHOT_CONTAINER);
|
||||
|
||||
pathcpy(vol, sizeof(vol), container);
|
||||
pathcat(vol, sizeof(vol), "/" SNAPSHOT_PENDING);
|
||||
if (is_dir(vol)) {
|
||||
pathcat(vol, sizeof(vol), "/" SNAPSHOT_PENDING "/");
|
||||
pathcat(vol, sizeof(vol), disk->mount_point + root_len);
|
||||
if (state_snapshot_dir(vol, disk) == 0) {
|
||||
msg_progress("Using disk %s pending snapshot...\n", disk->name);
|
||||
pathcpy(disk->dir, sizeof(disk->dir), vol);
|
||||
pathcat(disk->dir, sizeof(disk->dir), "/");
|
||||
pathcat(disk->dir, sizeof(disk->dir), disk->mount_point + root_len);
|
||||
} else {
|
||||
pathcpy(vol, sizeof(vol), container);
|
||||
pathcat(vol, sizeof(vol), "/" SNAPSHOT_STABLE);
|
||||
if (is_dir(vol)) {
|
||||
pathcat(vol, sizeof(vol), "/" SNAPSHOT_STABLE "/");
|
||||
pathcat(vol, sizeof(vol), disk->mount_point + root_len);
|
||||
if (state_snapshot_dir(vol, disk) == 0) {
|
||||
msg_progress("Using disk %s stable snapshot...\n", disk->name);
|
||||
pathcpy(disk->dir, sizeof(disk->dir), vol);
|
||||
pathcat(disk->dir, sizeof(disk->dir), "/");
|
||||
pathcat(disk->dir, sizeof(disk->dir), disk->mount_point + root_len);
|
||||
} else {
|
||||
/* fallback to standard mount point */
|
||||
msg_progress("Using disk %s live filesystem...\n", disk->name);
|
||||
}
|
||||
}
|
||||
|
|
@ -6013,37 +5997,32 @@ void state_snapshot_write(struct snapraid_state* state, tommy_list* filterlist_d
|
|||
pathcat(container, sizeof(container), SNAPSHOT_CONTAINER);
|
||||
|
||||
pathcpy(vol, sizeof(vol), container);
|
||||
pathcat(vol, sizeof(vol), "/" SNAPSHOT_PENDING);
|
||||
if (is_dir(vol)) {
|
||||
pathcat(vol, sizeof(vol), "/" SNAPSHOT_PENDING "/");
|
||||
pathcat(vol, sizeof(vol), disk->mount_point + root_len);
|
||||
if (state_snapshot_dir(vol, disk) == 0) {
|
||||
msg_progress("Using disk %s pending snapshot...\n", disk->name);
|
||||
pathcpy(disk->dir, sizeof(disk->dir), vol);
|
||||
pathcat(disk->dir, sizeof(disk->dir), "/");
|
||||
pathcat(disk->dir, sizeof(disk->dir), disk->mount_point + root_len);
|
||||
|
||||
/* if there is a dealloc list */
|
||||
if (!tommy_list_empty(&disk->dealloclist)) {
|
||||
pathcpy(vol, sizeof(vol), container);
|
||||
pathcat(vol, sizeof(vol), "/" SNAPSHOT_STABLE);
|
||||
pathcat(vol, sizeof(vol), "/" SNAPSHOT_STABLE "/");
|
||||
pathcat(vol, sizeof(vol), disk->mount_point + root_len);
|
||||
|
||||
/* if there is a previous snapshot */
|
||||
if (is_dir(vol)) {
|
||||
pathcat(vol, sizeof(vol), "/");
|
||||
pathcat(vol, sizeof(vol), disk->mount_point + root_len);
|
||||
|
||||
msg_progress("Importing disk %s stable snapshot deallocated files...\n", disk->name);
|
||||
if (state_snapshot_dir(vol, 0) == 0) {
|
||||
msg_progress("Importing disk %s stable snapshot %" PRIu64 " deallocated files...\n", disk->name, tommy_list_count(&disk->dealloclist));
|
||||
|
||||
state_dealloc(state, vol, &disk->dealloclist);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pathcpy(vol, sizeof(vol), container);
|
||||
pathcat(vol, sizeof(vol), "/" SNAPSHOT_STABLE);
|
||||
if (is_dir(vol)) {
|
||||
pathcat(vol, sizeof(vol), "/" SNAPSHOT_STABLE "/");
|
||||
pathcat(vol, sizeof(vol), disk->mount_point + root_len);
|
||||
if (state_snapshot_dir(vol, disk) == 0) {
|
||||
msg_progress("Using disk %s stable snapshot...\n", disk->name);
|
||||
pathcpy(disk->dir, sizeof(disk->dir), vol);
|
||||
pathcat(disk->dir, sizeof(disk->dir), "/");
|
||||
pathcat(disk->dir, sizeof(disk->dir), disk->mount_point + root_len);
|
||||
} else {
|
||||
/* fallback to standard mount point */
|
||||
msg_progress("Using disk %s live filesystem...\n", disk->name);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ void state_thermal(struct snapraid_state* state, time_t now)
|
|||
|
||||
entry = calloc_nofail(1, sizeof(devinfo_t));
|
||||
|
||||
entry->device = disk->device;
|
||||
entry->device = disk->mount_device;
|
||||
device_name_set(entry, disk->name, 0);
|
||||
pathcpy(entry->mount, sizeof(entry->mount), disk->mount_point);
|
||||
pathcpy(entry->smartctl, sizeof(entry->smartctl), disk->smartctl);
|
||||
|
|
|
|||
|
|
@ -1461,7 +1461,7 @@ int fssnapshot_create(const char* source, const char* parent_dir, const char* na
|
|||
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.fd = fd_source;
|
||||
args.flags = 0;
|
||||
args.flags = BTRFS_SUBVOL_RDONLY;
|
||||
pathcpy(args.name, BTRFS_SUBVOL_NAME_MAX, name);
|
||||
|
||||
/* issue the snapshot command to the PARENT directory of the destination */
|
||||
|
|
@ -1485,42 +1485,6 @@ int fssnapshot_create(const char* source, const char* parent_dir, const char* na
|
|||
#endif
|
||||
}
|
||||
|
||||
int fssnapshot_readonly(const char* parent_dir, const char* name)
|
||||
{
|
||||
#if HAVE_LINUX_DEVICE
|
||||
char path[PATH_MAX];
|
||||
|
||||
pathcpy(path, sizeof(path), parent_dir);
|
||||
pathcatc(path, sizeof(path), '/');
|
||||
pathcat(path, sizeof(path), name);
|
||||
|
||||
int fd = open(path, O_RDONLY | O_DIRECTORY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
/* get existing flags to avoid overwriting other potential flags */
|
||||
__u64 flags;
|
||||
if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
flags |= BTRFS_SUBVOL_RDONLY;
|
||||
|
||||
if (ioctl(fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags) < 0) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
#else
|
||||
(void)parent_dir;
|
||||
(void)name;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
int fssnapshot_delete(const char* parent_dir, const char* name)
|
||||
{
|
||||
#if HAVE_LINUX_DEVICE
|
||||
|
|
|
|||
113
doc/snapraid.1
113
doc/snapraid.1
|
|
@ -1436,9 +1436,10 @@ filesystem. Parity disks, or data disks using other filesystems, will
|
|||
always use the live version of the filesystem.
|
||||
.PP
|
||||
When enabled, SnapRAID ensures atomic and consistent operations by
|
||||
reading from a frozen point\-in\-time image. This prevents errors caused
|
||||
by file modifications during execution and ensures that deleted files
|
||||
remain available for parity\-based recovery of other disks.
|
||||
reading from a frozen point\-in\-time image. This prevents errors
|
||||
caused by file modifications during execution and ensures that
|
||||
updated and deleted files remain available for parity\-based
|
||||
recovery of other disks.
|
||||
.PP
|
||||
See the SNAPSHOTS section for more details.
|
||||
.SS nohidden
|
||||
|
|
@ -1794,12 +1795,13 @@ sync or scrub will not cause parity mismatches or aborted
|
|||
operations, as SnapRAID sees a frozen point\-in\-time image.
|
||||
.HP 4
|
||||
.I Recovery
|
||||
If a file is deleted from the live filesystem, it remains
|
||||
preserved in the snapshot. If a disk failure occurs before the
|
||||
next sync is run, SnapRAID uses the data preserved in the
|
||||
snapshot to reconstruct the failed disk. Without snapshots,
|
||||
a deleted file on a healthy disk results in missing data
|
||||
blocks that may be required to fix other failed disks.
|
||||
If a file is updated or deleted from the live filesystem,
|
||||
it remains preserved in the snapshot. If a disk failure occurs
|
||||
before the next sync is run, SnapRAID uses the data preserved
|
||||
in the snapshot to reconstruct the failed disk.
|
||||
Without snapshots, an updated or deleted file on a healthy
|
||||
disk results in missing data blocks that may be required to
|
||||
fix other failed disks.
|
||||
.PD
|
||||
.RE
|
||||
.PP
|
||||
|
|
@ -1813,9 +1815,9 @@ to operate directly on the live filesystem.
|
|||
.SS Command Behavior with Snapshots
|
||||
The \`sync\` and \`scrub\` commands both operate exclusively on snapshots
|
||||
to ensure that all data operations are performed against a consistent,
|
||||
frozen state. By utilizing these snapshots, SnapRAID prevents false
|
||||
positives and parity mismatches that would otherwise be triggered
|
||||
by concurrent file modifications on the live filesystem.
|
||||
frozen state. By utilizing these snapshots, SnapRAID prevents parity
|
||||
mismatches that would otherwise be triggered by concurrent file
|
||||
modifications on the live filesystem.
|
||||
During a \`sync\`, the command uses a new snapshot created at the
|
||||
start of the process to capture the current state for parity computation.
|
||||
In contrast, the \`scrub\` command utilizes the last snapshot, the one
|
||||
|
|
@ -1837,67 +1839,38 @@ provided, SnapRAID assumes the operation applies to the entire array,
|
|||
in this case, \`check\` and \`fix\` will use the live filesystems exclusively.
|
||||
.PP
|
||||
All other commands operate exclusively on the live filesystem.
|
||||
.SS Sync Safety
|
||||
To ensure maximum data safety during a sync operation, it is
|
||||
recommended to place the .content files inside the same subvolume
|
||||
used for the data, ensuring they are also part of the snapshots.
|
||||
.SH SNAPSHOTS LIFECYCLE
|
||||
SnapRAID manages two specific snapshots, \`stable\` and \`pending\`,
|
||||
within a hidden \`.snapraid\` directory at the root of each data
|
||||
subvolume.
|
||||
.PP
|
||||
When a sync starts, SnapRAID immediately updates the .content file to
|
||||
reflect the current state of the filesystem. If you have deleted files
|
||||
on a disk, the new .content file loses the metadata for those
|
||||
deleted items and their relation to the parity.
|
||||
The \`stable\` snapshot represents the state of the last
|
||||
successfully completed \`sync\`, containing the exact data used to
|
||||
compute the current parity. It serves as the primary data source
|
||||
for \`scrub\`, \`check\`, and \`fix\` commands.
|
||||
.PP
|
||||
If a disk fails while a \`sync\` is running, the parity for that
|
||||
failed disk may still depend on the deleted files.
|
||||
Even if your snapshot physically contains the deleted files,
|
||||
the new .content file no longer knows how they relate to the
|
||||
parity blocks. This missing correlation can prevent a full recovery.
|
||||
.PP
|
||||
Note that this specific risk only exists if a disk fails during
|
||||
an active sync. If a disk fails between syncs, the snapshot
|
||||
already contains data that is perfectly matched with the
|
||||
last successfully saved content file on the live filesystem,
|
||||
ensuring a successful recovery.
|
||||
.PP
|
||||
By storing the .content file inside the snapshotted subvolume, the
|
||||
snapshot preserves an older version of the content file, and
|
||||
the metadata within it, alongside the corresponding version of
|
||||
the data.
|
||||
.SS Snapshots Lifecycle
|
||||
SnapRAID manages two specific snapshots within a hidden \`.snapraid\`
|
||||
directory at the root of each data subvolume:
|
||||
.RS 0
|
||||
.PD 0
|
||||
.HP 4
|
||||
.I stable
|
||||
The reference snapshot representing the state of the last
|
||||
successfully completed \`sync\`. This snapshot contains the exact
|
||||
data used to compute the parity and serves as the primary data
|
||||
source for all \`scrub\`, \`check\`, and \`fix\` commands, provided
|
||||
that a pending snapshot is not present.
|
||||
.HP 4
|
||||
.I pending
|
||||
A temporary snapshot created at the start of a sync operation.
|
||||
Upon the successful completion of a sync, the previous stable
|
||||
The \`pending\` snapshot is a temporary image created at the start
|
||||
of a \`sync\` to provide a frozen state for parity computation.
|
||||
Upon successful completion of the operation, the previous stable
|
||||
snapshot is deleted, and the pending snapshot is promoted to
|
||||
stable.
|
||||
During this promotion, if a content file is stored on the
|
||||
same subvolume of the data, the final version of the content
|
||||
file is cloned (via reflink) into the snapshot.
|
||||
This ensures that the snapshot contains a metadata map that
|
||||
is perfectly in sync with the data blocks it preserves.
|
||||
Once promoted, the stable snapshot is set to a read\-only
|
||||
state to ensure its integrity as a recovery reference.
|
||||
If the sync fails or is interrupted, the pending snapshot is
|
||||
preserved in its current state. This allows subsequent \`scrub\`,
|
||||
\`check\`, and \`fix\` commands to function correctly by using the
|
||||
exact filesystem state recorded in the live content file,
|
||||
even if the parity is only partially synchronized.
|
||||
When sync is restarted after the interruption, the existing
|
||||
pending snapshot is deleted and a new one is created,
|
||||
capturing the new state of the live filesystem.
|
||||
.PD
|
||||
.RE
|
||||
take its place as the new stable reference.
|
||||
.PP
|
||||
If a \`sync\` is interrupted, the \`pending\` snapshot is preserved.
|
||||
Subsequent \`scrub\`, \`check\`, and \`fix\` commands will use this
|
||||
pending snapshot as it matches the filesystem state recorded in
|
||||
the .content file, even if the parity is only partially synchronized.
|
||||
.PP
|
||||
In the event of a \`sync\` interruption, \`check\` and \`fix\` commands
|
||||
can also read from the \`stable\` snapshot to retrieve data blocks
|
||||
from files that were updated or deleted during the sync.
|
||||
This is possible because the .content file retains metadata for
|
||||
all modified or deleted files throughout the sync process.
|
||||
This historical information is only cleared once a sync finishes
|
||||
successfully and the final version of the .content file is saved.
|
||||
.PP
|
||||
If a \`sync\` is restarted after an interruption, the existing
|
||||
pending snapshot is deleted and a new one is created to
|
||||
capture the current state of the live filesystem.
|
||||
.SH PATTERN
|
||||
Patterns are used to select a subset of files to exclude or include in
|
||||
the process. Globbing characters can be used to match files and paths
|
||||
|
|
|
|||
103
doc/snapraid.d
103
doc/snapraid.d
|
|
@ -1156,9 +1156,10 @@ Configuration
|
|||
always use the live version of the filesystem.
|
||||
|
||||
When enabled, SnapRAID ensures atomic and consistent operations by
|
||||
reading from a frozen point-in-time image. This prevents errors caused
|
||||
by file modifications during execution and ensures that deleted files
|
||||
remain available for parity-based recovery of other disks.
|
||||
reading from a frozen point-in-time image. This prevents errors
|
||||
caused by file modifications during execution and ensures that
|
||||
updated and deleted files remain available for parity-based
|
||||
recovery of other disks.
|
||||
|
||||
See the SNAPSHOTS section for more details.
|
||||
|
||||
|
|
@ -1414,12 +1415,13 @@ Snapshots
|
|||
Consistency - Files modified on the live filesystem during a long-running
|
||||
sync or scrub will not cause parity mismatches or aborted
|
||||
operations, as SnapRAID sees a frozen point-in-time image.
|
||||
Recovery - If a file is deleted from the live filesystem, it remains
|
||||
preserved in the snapshot. If a disk failure occurs before the
|
||||
next sync is run, SnapRAID uses the data preserved in the
|
||||
snapshot to reconstruct the failed disk. Without snapshots,
|
||||
a deleted file on a healthy disk results in missing data
|
||||
blocks that may be required to fix other failed disks.
|
||||
Recovery - If a file is updated or deleted from the live filesystem,
|
||||
it remains preserved in the snapshot. If a disk failure occurs
|
||||
before the next sync is run, SnapRAID uses the data preserved
|
||||
in the snapshot to reconstruct the failed disk.
|
||||
Without snapshots, an updated or deleted file on a healthy
|
||||
disk results in missing data blocks that may be required to
|
||||
fix other failed disks.
|
||||
|
||||
Snapshots are created only for data disks and only if the underlying
|
||||
filesystem supports this functionality. Parity disks always use
|
||||
|
|
@ -1432,9 +1434,9 @@ Snapshots
|
|||
Command Behavior with Snapshots
|
||||
The `sync` and `scrub` commands both operate exclusively on snapshots
|
||||
to ensure that all data operations are performed against a consistent,
|
||||
frozen state. By utilizing these snapshots, SnapRAID prevents false
|
||||
positives and parity mismatches that would otherwise be triggered
|
||||
by concurrent file modifications on the live filesystem.
|
||||
frozen state. By utilizing these snapshots, SnapRAID prevents parity
|
||||
mismatches that would otherwise be triggered by concurrent file
|
||||
modifications on the live filesystem.
|
||||
During a `sync`, the command uses a new snapshot created at the
|
||||
start of the process to capture the current state for parity computation.
|
||||
In contrast, the `scrub` command utilizes the last snapshot, the one
|
||||
|
|
@ -1457,61 +1459,38 @@ Snapshots
|
|||
|
||||
All other commands operate exclusively on the live filesystem.
|
||||
|
||||
Sync Safety
|
||||
To ensure maximum data safety during a sync operation, it is
|
||||
recommended to place the .content files inside the same subvolume
|
||||
used for the data, ensuring they are also part of the snapshots.
|
||||
Snapshots Lifecycle
|
||||
SnapRAID manages two specific snapshots, `stable` and `pending`,
|
||||
within a hidden `.snapraid` directory at the root of each data
|
||||
subvolume.
|
||||
|
||||
When a sync starts, SnapRAID immediately updates the .content file to
|
||||
reflect the current state of the filesystem. If you have deleted files
|
||||
on a disk, the new .content file loses the metadata for those
|
||||
deleted items and their relation to the parity.
|
||||
The `stable` snapshot represents the state of the last
|
||||
successfully completed `sync`, containing the exact data used to
|
||||
compute the current parity. It serves as the primary data source
|
||||
for `scrub`, `check`, and `fix` commands.
|
||||
|
||||
If a disk fails while a `sync` is running, the parity for that
|
||||
failed disk may still depend on the deleted files.
|
||||
Even if your snapshot physically contains the deleted files,
|
||||
the new .content file no longer knows how they relate to the
|
||||
parity blocks. This missing correlation can prevent a full recovery.
|
||||
The `pending` snapshot is a temporary image created at the start
|
||||
of a `sync` to provide a frozen state for parity computation.
|
||||
Upon successful completion of the operation, the previous stable
|
||||
snapshot is deleted, and the pending snapshot is promoted to
|
||||
take its place as the new stable reference.
|
||||
|
||||
Note that this specific risk only exists if a disk fails during
|
||||
an active sync. If a disk fails between syncs, the snapshot
|
||||
already contains data that is perfectly matched with the
|
||||
last successfully saved content file on the live filesystem,
|
||||
ensuring a successful recovery.
|
||||
If a `sync` is interrupted, the `pending` snapshot is preserved.
|
||||
Subsequent `scrub`, `check`, and `fix` commands will use this
|
||||
pending snapshot as it matches the filesystem state recorded in
|
||||
the .content file, even if the parity is only partially synchronized.
|
||||
|
||||
By storing the .content file inside the snapshotted subvolume, the
|
||||
snapshot preserves an older version of the content file, and
|
||||
the metadata within it, alongside the corresponding version of
|
||||
the data.
|
||||
In the event of a `sync` interruption, `check` and `fix` commands
|
||||
can also read from the `stable` snapshot to retrieve data blocks
|
||||
from files that were updated or deleted during the sync.
|
||||
This is possible because the .content file retains metadata for
|
||||
all modified or deleted files throughout the sync process.
|
||||
This historical information is only cleared once a sync finishes
|
||||
successfully and the final version of the .content file is saved.
|
||||
|
||||
Snapshots Lifecycle
|
||||
SnapRAID manages two specific snapshots within a hidden `.snapraid`
|
||||
directory at the root of each data subvolume:
|
||||
|
||||
stable - The reference snapshot representing the state of the last
|
||||
successfully completed `sync`. This snapshot contains the exact
|
||||
data used to compute the parity and serves as the primary data
|
||||
source for all `scrub`, `check`, and `fix` commands, provided
|
||||
that a pending snapshot is not present.
|
||||
pending - A temporary snapshot created at the start of a sync operation.
|
||||
Upon the successful completion of a sync, the previous stable
|
||||
snapshot is deleted, and the pending snapshot is promoted to
|
||||
stable.
|
||||
During this promotion, if a content file is stored on the
|
||||
same subvolume of the data, the final version of the content
|
||||
file is cloned (via reflink) into the snapshot.
|
||||
This ensures that the snapshot contains a metadata map that
|
||||
is perfectly in sync with the data blocks it preserves.
|
||||
Once promoted, the stable snapshot is set to a read-only
|
||||
state to ensure its integrity as a recovery reference.
|
||||
If the sync fails or is interrupted, the pending snapshot is
|
||||
preserved in its current state. This allows subsequent `scrub`,
|
||||
`check`, and `fix` commands to function correctly by using the
|
||||
exact filesystem state recorded in the live content file,
|
||||
even if the parity is only partially synchronized.
|
||||
When sync is restarted after the interruption, the existing
|
||||
pending snapshot is deleted and a new one is created,
|
||||
capturing the new state of the live filesystem.
|
||||
If a `sync` is restarted after an interruption, the existing
|
||||
pending snapshot is deleted and a new one is created to
|
||||
capture the current state of the live filesystem.
|
||||
|
||||
Pattern
|
||||
Patterns are used to select a subset of files to exclude or include in
|
||||
|
|
|
|||
124
doc/snapraid.txt
124
doc/snapraid.txt
|
|
@ -1234,9 +1234,10 @@ filesystem. Parity disks, or data disks using other filesystems, will
|
|||
always use the live version of the filesystem.
|
||||
|
||||
When enabled, SnapRAID ensures atomic and consistent operations by
|
||||
reading from a frozen point-in-time image. This prevents errors caused
|
||||
by file modifications during execution and ensures that deleted files
|
||||
remain available for parity-based recovery of other disks.
|
||||
reading from a frozen point-in-time image. This prevents errors
|
||||
caused by file modifications during execution and ensures that
|
||||
updated and deleted files remain available for parity-based
|
||||
recovery of other disks.
|
||||
|
||||
See the SNAPSHOTS section for more details.
|
||||
|
||||
|
|
@ -1519,12 +1520,13 @@ This provides two primary benefits:
|
|||
Consistency - Files modified on the live filesystem during a long-running
|
||||
sync or scrub will not cause parity mismatches or aborted
|
||||
operations, as SnapRAID sees a frozen point-in-time image.
|
||||
Recovery - If a file is deleted from the live filesystem, it remains
|
||||
preserved in the snapshot. If a disk failure occurs before the
|
||||
next sync is run, SnapRAID uses the data preserved in the
|
||||
snapshot to reconstruct the failed disk. Without snapshots,
|
||||
a deleted file on a healthy disk results in missing data
|
||||
blocks that may be required to fix other failed disks.
|
||||
Recovery - If a file is updated or deleted from the live filesystem,
|
||||
it remains preserved in the snapshot. If a disk failure occurs
|
||||
before the next sync is run, SnapRAID uses the data preserved
|
||||
in the snapshot to reconstruct the failed disk.
|
||||
Without snapshots, an updated or deleted file on a healthy
|
||||
disk results in missing data blocks that may be required to
|
||||
fix other failed disks.
|
||||
|
||||
Snapshots are created only for data disks and only if the underlying
|
||||
filesystem supports this functionality. Parity disks always use
|
||||
|
|
@ -1539,9 +1541,9 @@ to operate directly on the live filesystem.
|
|||
|
||||
The `sync` and `scrub` commands both operate exclusively on snapshots
|
||||
to ensure that all data operations are performed against a consistent,
|
||||
frozen state. By utilizing these snapshots, SnapRAID prevents false
|
||||
positives and parity mismatches that would otherwise be triggered
|
||||
by concurrent file modifications on the live filesystem.
|
||||
frozen state. By utilizing these snapshots, SnapRAID prevents parity
|
||||
mismatches that would otherwise be triggered by concurrent file
|
||||
modifications on the live filesystem.
|
||||
During a `sync`, the command uses a new snapshot created at the
|
||||
start of the process to capture the current state for parity computation.
|
||||
In contrast, the `scrub` command utilizes the last snapshot, the one
|
||||
|
|
@ -1564,69 +1566,45 @@ in this case, `check` and `fix` will use the live filesystems exclusively.
|
|||
|
||||
All other commands operate exclusively on the live filesystem.
|
||||
|
||||
8.2 Sync Safety
|
||||
---------------
|
||||
|
||||
To ensure maximum data safety during a sync operation, it is
|
||||
recommended to place the .content files inside the same subvolume
|
||||
used for the data, ensuring they are also part of the snapshots.
|
||||
9 SNAPSHOTS LIFECYCLE
|
||||
=====================
|
||||
|
||||
When a sync starts, SnapRAID immediately updates the .content file to
|
||||
reflect the current state of the filesystem. If you have deleted files
|
||||
on a disk, the new .content file loses the metadata for those
|
||||
deleted items and their relation to the parity.
|
||||
SnapRAID manages two specific snapshots, `stable` and `pending`,
|
||||
within a hidden `.snapraid` directory at the root of each data
|
||||
subvolume.
|
||||
|
||||
If a disk fails while a `sync` is running, the parity for that
|
||||
failed disk may still depend on the deleted files.
|
||||
Even if your snapshot physically contains the deleted files,
|
||||
the new .content file no longer knows how they relate to the
|
||||
parity blocks. This missing correlation can prevent a full recovery.
|
||||
The `stable` snapshot represents the state of the last
|
||||
successfully completed `sync`, containing the exact data used to
|
||||
compute the current parity. It serves as the primary data source
|
||||
for `scrub`, `check`, and `fix` commands.
|
||||
|
||||
Note that this specific risk only exists if a disk fails during
|
||||
an active sync. If a disk fails between syncs, the snapshot
|
||||
already contains data that is perfectly matched with the
|
||||
last successfully saved content file on the live filesystem,
|
||||
ensuring a successful recovery.
|
||||
The `pending` snapshot is a temporary image created at the start
|
||||
of a `sync` to provide a frozen state for parity computation.
|
||||
Upon successful completion of the operation, the previous stable
|
||||
snapshot is deleted, and the pending snapshot is promoted to
|
||||
take its place as the new stable reference.
|
||||
|
||||
By storing the .content file inside the snapshotted subvolume, the
|
||||
snapshot preserves an older version of the content file, and
|
||||
the metadata within it, alongside the corresponding version of
|
||||
the data.
|
||||
If a `sync` is interrupted, the `pending` snapshot is preserved.
|
||||
Subsequent `scrub`, `check`, and `fix` commands will use this
|
||||
pending snapshot as it matches the filesystem state recorded in
|
||||
the .content file, even if the parity is only partially synchronized.
|
||||
|
||||
8.3 Snapshots Lifecycle
|
||||
-----------------------
|
||||
In the event of a `sync` interruption, `check` and `fix` commands
|
||||
can also read from the `stable` snapshot to retrieve data blocks
|
||||
from files that were updated or deleted during the sync.
|
||||
This is possible because the .content file retains metadata for
|
||||
all modified or deleted files throughout the sync process.
|
||||
This historical information is only cleared once a sync finishes
|
||||
successfully and the final version of the .content file is saved.
|
||||
|
||||
SnapRAID manages two specific snapshots within a hidden `.snapraid`
|
||||
directory at the root of each data subvolume:
|
||||
|
||||
stable - The reference snapshot representing the state of the last
|
||||
successfully completed `sync`. This snapshot contains the exact
|
||||
data used to compute the parity and serves as the primary data
|
||||
source for all `scrub`, `check`, and `fix` commands, provided
|
||||
that a pending snapshot is not present.
|
||||
pending - A temporary snapshot created at the start of a sync operation.
|
||||
Upon the successful completion of a sync, the previous stable
|
||||
snapshot is deleted, and the pending snapshot is promoted to
|
||||
stable.
|
||||
During this promotion, if a content file is stored on the
|
||||
same subvolume of the data, the final version of the content
|
||||
file is cloned (via reflink) into the snapshot.
|
||||
This ensures that the snapshot contains a metadata map that
|
||||
is perfectly in sync with the data blocks it preserves.
|
||||
Once promoted, the stable snapshot is set to a read-only
|
||||
state to ensure its integrity as a recovery reference.
|
||||
If the sync fails or is interrupted, the pending snapshot is
|
||||
preserved in its current state. This allows subsequent `scrub`,
|
||||
`check`, and `fix` commands to function correctly by using the
|
||||
exact filesystem state recorded in the live content file,
|
||||
even if the parity is only partially synchronized.
|
||||
When sync is restarted after the interruption, the existing
|
||||
pending snapshot is deleted and a new one is created,
|
||||
capturing the new state of the live filesystem.
|
||||
If a `sync` is restarted after an interruption, the existing
|
||||
pending snapshot is deleted and a new one is created to
|
||||
capture the current state of the live filesystem.
|
||||
|
||||
|
||||
9 PATTERN
|
||||
=========
|
||||
10 PATTERN
|
||||
==========
|
||||
|
||||
Patterns are used to select a subset of files to exclude or include in
|
||||
the process. Globbing characters can be used to match files and paths
|
||||
|
|
@ -1743,7 +1721,7 @@ In Unix, when using globbing characters on the command line, you must
|
|||
quote them to prevent the shell from expanding them.
|
||||
|
||||
|
||||
10 IGNORE FILE
|
||||
11 IGNORE FILE
|
||||
==============
|
||||
|
||||
In addition to the global rules in the configuration file, you can
|
||||
|
|
@ -1788,7 +1766,7 @@ For example, if you have a `.snapraidignore` in `/mnt/disk1/projects/`:
|
|||
*.tmp
|
||||
|
||||
|
||||
11 CONTENT
|
||||
12 CONTENT
|
||||
==========
|
||||
|
||||
SnapRAID stores the list and checksums of your files in the content file.
|
||||
|
|
@ -1800,7 +1778,7 @@ This file is read and written by the `sync` and `scrub` commands and
|
|||
read by the `fix`, `check`, and `status` commands.
|
||||
|
||||
|
||||
12 PARITY
|
||||
13 PARITY
|
||||
=========
|
||||
|
||||
SnapRAID stores the parity information of your array in the parity
|
||||
|
|
@ -1813,7 +1791,7 @@ These files are read and written by the `sync` and `fix` commands and
|
|||
only read by the `scrub` and `check` commands.
|
||||
|
||||
|
||||
13 ENCODING
|
||||
14 ENCODING
|
||||
===========
|
||||
|
||||
SnapRAID in Unix ignores any encoding. It reads and stores the
|
||||
|
|
@ -1830,7 +1808,7 @@ redirect the console output to a file, the resulting file is always
|
|||
in UTF-8 format.
|
||||
|
||||
|
||||
14 EXIT CODE
|
||||
15 EXIT CODE
|
||||
============
|
||||
|
||||
SnapRAID terminates with the following error codes:
|
||||
|
|
@ -1841,13 +1819,13 @@ SnapRAID terminates with the following error codes:
|
|||
needed.
|
||||
|
||||
|
||||
15 COPYRIGHT
|
||||
16 COPYRIGHT
|
||||
============
|
||||
|
||||
This file is Copyright (C) 2026 Andrea Mazzoleni
|
||||
|
||||
|
||||
16 SEE ALSO
|
||||
17 SEE ALSO
|
||||
===========
|
||||
|
||||
snapraid_log(1), snapraidd(1), rsync(1)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue