Add regression check for Btrfs

It requires root privileges as it has to create Btrfs filesystems.
This commit is contained in:
Andrea Mazzoleni 2026-04-28 11:51:59 +02:00
parent c843812bb0
commit f791f76b4e
7 changed files with 142 additions and 59 deletions

View file

@ -210,12 +210,12 @@ void cmd_generate_symlink(const char* path, const char* linkto)
/**
* Create a file or a symlink with a random name.
*/
void cmd_generate(int disk, int size)
void cmd_generate(const char* tag, int disk, int size)
{
char path[PATH_MAX];
char* file;
snprintf(path, sizeof(path), "bench/disk%d/", disk);
snprintf(path, sizeof(path), "bench/%s%d/", tag, disk);
file = path + strlen(path);
/* add a directory */
@ -627,9 +627,9 @@ void help(void)
{
printf("Test for " PACKAGE " v" VERSION " by Andrea Mazzoleni, " PACKAGE_URL "\n");
printf("Usage:\n");
printf("\tmktest generate SEED DISK_NUM FILE_NUM FILE_SIZE\n");
printf("\tmktest damage SEED NUM SIZE FILE\n");
printf("\tmktest write SEED NUM SIZE FILE\n");
printf("\tmktest generate SEED DISK_TAG DISK_NUM FILE_NUM FILE_SIZE\n");
printf("\tmktest damage SEED COUNT SIZE FILE\n");
printf("\tmktest write SEED COUNT SIZE FILE\n");
printf("\tmktest change SEED SIZE FILE\n");
printf("\tmktest append SEED SIZE FILE\n");
printf("\tmktest truncate SEED SIZE FILE\n");
@ -648,8 +648,9 @@ int main(int argc, char* argv[])
if (strcmp(argv[1], "generate") == 0) {
int disk, file, size;
const char* tag;
if (argc != 6) {
if (argc != 7) {
/* LCOV_EXCL_START */
help();
exit(EXIT_FAILURE);
@ -657,20 +658,21 @@ int main(int argc, char* argv[])
}
seed = atoi(argv[2]);
disk = atoi(argv[3]);
file = atoi(argv[4]);
size = atoi(argv[5]);
tag = argv[3];
disk = atoi(argv[4]);
file = atoi(argv[5]);
size = atoi(argv[6]);
for (i = 0; i < disk; ++i) {
for (j = 0; j < file; ++j) {
if (j == 0)
/* create at least a big one */
cmd_generate(i + 1, size);
cmd_generate(tag, i + 1, size);
else if (j == 1)
/* create at least an empty one */
cmd_generate(i + 1, 0);
cmd_generate(tag, i + 1, 0);
else
cmd_generate(i + 1, rnd(size));
cmd_generate(tag, i + 1, rnd(size));
}
}
} else if (strcmp(argv[1], "write") == 0) {

View file

@ -659,6 +659,7 @@ void log_close(const char* file)
#define OPT_TEST_SPEED_PERIOD 307
#define OPT_TEST_SPEED_DISKS_NUMBER 308
#define OPT_TEST_SPEED_BLOCKS_SIZE 309
#define OPT_TEST_KILL_BEFORE_SYNC 310
#if HAVE_GETOPT_LONG
@ -714,6 +715,9 @@ static struct option long_options[] = {
/* After syncing, do not write the new content file */
{ "test-kill-after-sync", 0, 0, OPT_TEST_KILL_AFTER_SYNC },
/* Do not execure syncing after writing the new initial content file */
{ "test-kill-before-sync", 0, 0, OPT_TEST_KILL_BEFORE_SYNC },
/* Exit with failure if after check/fix there ARE NOT unrecoverable errors. */
{ "test-expect-unrecoverable", 0, 0, OPT_TEST_EXPECT_UNRECOVERABLE },
@ -1267,6 +1271,9 @@ int snapraid_main(int argc, char* argv[])
case OPT_TEST_KILL_AFTER_SYNC :
opt.kill_after_sync = 1;
break;
case OPT_TEST_KILL_BEFORE_SYNC :
opt.kill_before_sync = 1;
break;
case OPT_TEST_EXPECT_UNRECOVERABLE :
opt.expect_unrecoverable = 1;
break;

View file

@ -86,6 +86,7 @@ struct snapraid_option {
int skip_disk_access; /**< Skip the data disk access for commands that don't need it. */
int skip_content_access; /**< Skip the content access for commands that don't need it. */
int kill_after_sync; /**< Kill the process after sync without saving the final state. */
int kill_before_sync; /**< Kill the process before sync after saving the initial state. */
int force_murmur3; /**< Force Murmur3 choice. */
int force_spooky2; /**< Force Spooky2 choice. */
int force_order; /**< Force sorting order. One of the SORT_* defines. */

View file

@ -1431,14 +1431,15 @@ end:
/* now the parity is fully written, no need to keep deallocated files */
state_commit(state);
/* save the new state if required */
if (!state->opt.kill_after_sync) {
if ((state->need_write || state->opt.force_content_write))
state_write(state);
} else {
log_fatal(EUSER, "WARNING! Skipped writing state due to --test-kill-after-sync option.\n");
if (state->opt.kill_after_sync) {
log_fatal(EUSER, "WARNING! Killing due --test-kill-after-sync option.\n");
exit(EXIT_SUCCESS);
}
/* save the new state if required */
if ((state->need_write || state->opt.force_content_write))
state_write(state);
state_usage_print(state);
if (soft_error || silent_error || io_error) {
@ -1677,6 +1678,11 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t
log_fatal(EUSER, "WARNING! Skipped state write for --test-skip-content-write option.\n");
}
if (state->opt.kill_before_sync) {
log_fatal(EUSER, "WARNING! Killing due --test-kill-before-sync option.\n");
exit(EXIT_SUCCESS);
}
/* skip degenerated cases of empty parity, or skipping all */
if (blockstart < blockmax) {
ret = state_sync_process(state, parity_handle, blockstart, blockmax);