From cacc1cb0ce28a60c6f3f96a18601afd2b62635e2 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Mon, 28 Dec 2015 13:55:22 +0100 Subject: [PATCH] Autorename disks using UUID for matching --- HISTORY | 2 ++ Makefile.am | 5 +++ cmdline/snapraid.c | 7 ++++ cmdline/state.c | 69 +++++++++++++++++++++++++++++++------- cmdline/state.h | 1 + test/test-par6-rename.conf | 24 +++++++++++++ 6 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 test/test-par6-rename.conf diff --git a/HISTORY b/HISTORY index b9edf694..3cb255eb 100644 --- a/HISTORY +++ b/HISTORY @@ -6,6 +6,8 @@ SnapRAID HISTORY * Fixes support for symlinks pointing to an empty target. Before they were only partially supported, and their presence could result in a content file not readable. + * Autorename disks using the matching UUID. To rename a disk you can + now change directly the name in the configuration file. * Improves the physical offset ordering for the Btrfs filesystem, correctly detecting files that have not a physical offset, for whatever reason. diff --git a/Makefile.am b/Makefile.am index 39dcd149..ddf78386 100644 --- a/Makefile.am +++ b/Makefile.am @@ -118,6 +118,7 @@ EXTRA_DIST = \ test/test-par6.conf \ test/test-par6-hole.conf \ test/test-par6-noaccess.conf \ + test/test-par6-rename.conf \ snapraid.conf.example \ configure.windows-x86 configure.windows-x64 snapraid.conf.example.windows \ acinclude.m4 \ @@ -185,6 +186,7 @@ endif CONF = $(srcdir)/test/test-par6.conf HOLE = $(srcdir)/test/test-par6-hole.conf NOACCESS = $(srcdir)/test/test-par6-noaccess.conf +RENAME = $(srcdir)/test/test-par6-rename.conf PAR1 = $(srcdir)/test/test-par1.conf PAR2 = $(srcdir)/test/test-par2.conf PAR3 = $(srcdir)/test/test-par3.conf @@ -425,6 +427,9 @@ endif echo --- Fix with unaccessible parity and disk $(FAILENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(NOACCESS) fix --test-expect-failure $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(NOACCESS) fix --force-device --test-expect-recoverable -l test.log + echo -- Rename a disk + $(FAILENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(RENAME) --test-match-first-uuid sync + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-match-first-uuid sync #### SCRUB #### echo --- Scrub some times $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-force-scrub-at 100 scrub diff --git a/cmdline/snapraid.c b/cmdline/snapraid.c index 5b911dc8..0ecaa8e1 100644 --- a/cmdline/snapraid.c +++ b/cmdline/snapraid.c @@ -247,6 +247,7 @@ void config(char* conf, size_t conf_size, const char* argv0) #define OPT_TEST_EXPECT_NEED_SYNC 285 #define OPT_NO_WARNINGS 286 #define OPT_TEST_FAKE_UUID 287 +#define OPT_TEST_MATCH_FIRST_UUID 288 #if HAVE_GETOPT_LONG struct option long_options[] = { @@ -368,6 +369,9 @@ struct option long_options[] = { /* Fake UUID */ { "test-fake-uuid", 0, 0, OPT_TEST_FAKE_UUID }, + /* Match first UUID */ + { "test-match-first-uuid", 0, 0, OPT_TEST_MATCH_FIRST_UUID }, + { 0, 0, 0, 0 } }; #endif @@ -740,6 +744,9 @@ int main(int argc, char* argv[]) case OPT_TEST_FAKE_UUID : opt.fake_uuid = 2; break; + case OPT_TEST_MATCH_FIRST_UUID : + opt.match_first_uuid = 1; + break; default : /* LCOV_EXCL_START */ log_fatal("Unknown option '%c'\n", (char)c); diff --git a/cmdline/state.c b/cmdline/state.c index fb7ffa85..8956c4c4 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -1155,7 +1155,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co /** * Find a disk by name. */ -static struct snapraid_disk* find_disk(struct snapraid_state* state, const char* name) +static struct snapraid_disk* find_disk_by_name(struct snapraid_state* state, const char* name) { tommy_node* i; @@ -1179,6 +1179,39 @@ static struct snapraid_disk* find_disk(struct snapraid_state* state, const char* return 0; } +/** + * Find a disk by UUID. + */ +static struct snapraid_disk* find_disk_by_uuid(struct snapraid_state* state, const char* uuid) +{ + tommy_node* i; + struct snapraid_disk* found = 0; + + /* special test case to find the first macthing UUID */ + /* when testing UUID are all equal or not supported */ + /* and we should handle this case specifically */ + if (state->opt.match_first_uuid) + return state->disklist->data; + + /* LCOV_EXCL_START */ + /* never find an empty uuid */ + if (!*uuid) + return 0; + + for (i = state->disklist; i != 0; i = i->next) { + struct snapraid_disk* disk = i->data; + if (strcmp(disk->uuid, uuid) == 0) { + /* never match duplicate UUID */ + if (found) + return 0; + found = disk; + } + } + + return found; + /* LCOV_EXCL_STOP */ +} + /** * Update the disk mapping if required. */ @@ -1198,7 +1231,7 @@ static void state_map(struct snapraid_state* state) struct snapraid_map* map = i->data; struct snapraid_disk* disk; - disk = find_disk(state, map->name); + disk = find_disk_by_name(state, map->name); /* go to the next mapping before removing */ i = i->next; @@ -1270,7 +1303,7 @@ static void state_map(struct snapraid_state* state) struct snapraid_map* map = i->data; struct snapraid_disk* disk; - disk = find_disk(state, map->name); + disk = find_disk_by_name(state, map->name); if (disk == 0) { /* LCOV_EXCL_START */ log_fatal("Internal inconsistency for mapping '%s'\n", map->name); @@ -1398,7 +1431,7 @@ void state_refresh(struct snapraid_state* state) uint64_t free_space; int ret; - disk = find_disk(state, map->name); + disk = find_disk_by_name(state, map->name); if (disk == 0) { /* LCOV_EXCL_START */ log_fatal("Internal inconsistency for mapping '%s'\n", map->name); @@ -2375,21 +2408,31 @@ static void state_read_content(struct snapraid_state* state, const char* path, S /* LCOV_EXCL_STOP */ } - map = map_alloc(buffer, v_pos, v_total_blocks, v_free_blocks, uuid); - - tommy_list_insert_tail(&state->maplist, &map->node, map); - /* find the disk */ - disk = find_disk(state, buffer); + disk = find_disk_by_name(state, buffer); + if (!disk) { + /* search by UUID if renamed */ + disk = find_disk_by_uuid(state, uuid); + if (disk) { + log_fatal("WARNING! Renaming disk '%s' to '%s'\n", buffer, disk->name); + + /* write the new state with the new name */ + state->need_write = 1; + } + } if (!disk) { /* LCOV_EXCL_START */ decoding_error(path, f); - log_fatal("Disk named '%s' not present in the configuration file!\n", buffer); + log_fatal("Disk '%s' with uuid '%s' not present in the configuration file!\n", buffer, uuid); log_fatal("If you have removed it from the configuration file, please restore it\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } + map = map_alloc(disk->name, v_pos, v_total_blocks, v_free_blocks, uuid); + + tommy_list_insert_tail(&state->maplist, &map->node, map); + /* insert in the mapping vector */ tommy_array_grow(&disk_mapping, mapping_max + 1); tommy_array_set(&disk_mapping, mapping_max, disk); @@ -2638,7 +2681,7 @@ static void* state_write_thread(void* arg) struct snapraid_disk* disk; /* find the disk for this mapping */ - disk = find_disk(state, map->name); + disk = find_disk_by_name(state, map->name); if (!disk) { /* LCOV_EXCL_START */ log_fatal("Internal inconsistency for unmapped disk '%s'\n", map->name); @@ -3072,7 +3115,7 @@ static void state_write_content(struct snapraid_state* state, uint32_t* out_crc) struct snapraid_disk* disk; /* find the disk for this mapping */ - disk = find_disk(state, map->name); + disk = find_disk_by_name(state, map->name); if (!disk) { /* LCOV_EXCL_START */ log_fatal("Internal inconsistency for unmapped disk '%s'\n", map->name); @@ -3982,7 +4025,7 @@ void generate_configuration(const char* path) printf("# Set the correct dir for disk '%s'\n", map->name); if (map->uuid[0]) printf("# Disk '%s' is the one with id '%s'\n", map->name, map->uuid); - disk = find_disk(&state, map->name); + disk = find_disk_by_name(&state, map->name); if (disk && disk->filelist) { struct snapraid_file* file = disk->filelist->data; if (file) { diff --git a/cmdline/state.h b/cmdline/state.h index f36227b8..f86c90bf 100644 --- a/cmdline/state.h +++ b/cmdline/state.h @@ -106,6 +106,7 @@ struct snapraid_option { int no_warnings; /**< Remove some warning messages. */ int expected_missing; /**< If missing files are expected and should not be reported. */ int fake_uuid; /**< Set fakes UUID for testing. */ + int match_first_uuid; /**< Force the matching of the first UUID. */ }; /** diff --git a/test/test-par6-rename.conf b/test/test-par6-rename.conf new file mode 100644 index 00000000..cc7f6ce9 --- /dev/null +++ b/test/test-par6-rename.conf @@ -0,0 +1,24 @@ +blocksize 1 +parity bench/parity +2-parity bench/2-parity +3-parity bench/3-parity +4-parity bench/4-parity +5-parity bench/5-parity +6-parity bench/6-parity +content bench/content +content bench/1-content +content bench/2-content +content bench/3-content +content bench/4-content +content bench/5-content +content bench/6-content +disk disk1-rename bench/disk1/ +disk disk2 bench/disk2/ +disk disk3 bench/disk3/ +disk disk4 bench/disk4/ +disk disk5 bench/disk5/ +disk disk6 bench/disk6/ +include *.hidden +exclude *.unrecoverable + +