From 2b69cfa0733b2e2248859e172b98f40925e3ed1a Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Sat, 17 Oct 2015 17:36:40 +0200 Subject: [PATCH] Extend the disk filtering to parity disk You can now fix a specific parity disk, without touching the others. --- HISTORY | 8 +++++--- Makefile.am | 3 +-- cmdline/check.c | 28 ++++++++++++++++++---------- cmdline/elem.h | 1 + cmdline/snapraid.c | 9 +++++++++ cmdline/state.c | 36 ++++++++++++++++++++++++++++++++---- snapraid.1 | 2 ++ snapraid.d | 2 ++ snapraid.txt | 2 ++ 9 files changed, 72 insertions(+), 19 deletions(-) diff --git a/HISTORY b/HISTORY index ce992761..01e24d42 100644 --- a/HISTORY +++ b/HISTORY @@ -16,17 +16,19 @@ SnapRAID HISTORY ensure to scrub all the synced blocks. * The -p, --percentage option supports the new the arguments: "bad", "sync" and "full" to define the kind of scrub to do. - * Drastically reduced the memory usage. For each block, it now + * Drastically reduces the memory usage. For each block, it now uses 17 bytes of memory, instead of the previous 28 bytes (for 32 bit) or 36 bytes (for 64 bit). This could result is a memory saving of up the 50%. * Extends the -D, --force-device option to ignore more erroneous conditions in the 'fix' command, like unaccessible disks, or disks sharing the same physical device. + * Extends the -d, --filter-disk option to allow to filter also + by parity disk. * Extends the -h, --pre-hash option to also verify moved and copied files into the array before running a 'sync'. - * Update 'best' RAID functions for recent Atom CPUs. - * Validate filters specifications rejecting relative paths. + * Updates 'best' RAID functions for recent Atom CPUs. + * Validates filters specifications rejecting relative paths. 8.1 2015/05 =========== diff --git a/Makefile.am b/Makefile.am index 0f766e32..8c9a3807 100644 --- a/Makefile.am +++ b/Makefile.am @@ -366,8 +366,7 @@ if HAVE_SYMLINK endif echo --- Extend PAR1 to max parity with fix and check $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-expect-recoverable -c $(CONF) check -l test.log - $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) fix -l test.log - $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(PAR1) check + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) fix -d 2-parity -d 3-parity -d 4-parity -d 5-parity -d 6-parity -l test.log $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check #### SCRUB #### echo --- Scrub some times diff --git a/cmdline/check.c b/cmdline/check.c index 7f2b9415..a97b54d8 100644 --- a/cmdline/check.c +++ b/cmdline/check.c @@ -797,9 +797,9 @@ close_and_continue: */ static int block_is_enabled(struct snapraid_state* state, block_off_t i, struct snapraid_handle* handle, unsigned diskmax) { - int one_tocheck; snapraid_info info; unsigned j; + unsigned l; /* get block specific info */ info = info_get(&state->infoarr, i); @@ -811,8 +811,14 @@ static int block_is_enabled(struct snapraid_state* state, block_off_t i, struct return 0; } + /* for each parity */ + for (l = 0; l < state->level; ++l) { + if (!state->parity[l].is_excluded) { + return 1; + } + } + /* for each disk */ - one_tocheck = 0; for (j = 0; j < diskmax; ++j) { struct snapraid_block* block; @@ -827,17 +833,12 @@ static int block_is_enabled(struct snapraid_state* state, block_off_t i, struct if (block_has_file(block)) { struct snapraid_file* file = fs_par2file_get(handle[j].disk, i, 0); if (!file_flag_has(file, FILE_IS_EXCLUDED)) { /* only if the file is not filtered out */ - one_tocheck = 1; - break; + return 1; } } } - /* if no block to check skip */ - if (!one_tocheck) - return 0; - - return 1; + return 0; } static int state_check_process(struct snapraid_state* state, int fix, struct snapraid_parity_handle** parity, block_off_t blockstart, block_off_t blockmax) @@ -1270,6 +1271,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna if (buffer_recov[l] != 0 && memcmp(buffer_recov[l], buffer[diskmax + l], state->block_size) != 0) { unsigned diff = memdiff(buffer_recov[l], buffer[diskmax + l], state->block_size); + /* mark that the read parity is wrong, setting ptr to 0 */ buffer_recov[l] = 0; log_tag("parity_error:%u:%s: Data error, diff bits %u\n", i, lev_config_name(l), diff); @@ -1330,7 +1332,13 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna if (valid_parity) { /* update the parity */ for (l = 0; l < state->level; ++l) { - if (buffer_recov[l] == 0 && parity[l] != 0) { + /* if the parity on disk is wrong */ + if (buffer_recov[l] == 0 + /* and we have access at the parity */ + && parity[l] != 0 + /* and the parity is not excluded */ + && !state->parity[l].is_excluded + ) { ret = parity_write(parity[l], i, buffer[diskmax + l], state->block_size); if (ret == -1) { /* LCOV_EXCL_START */ diff --git a/cmdline/elem.h b/cmdline/elem.h index 1da3ba85..c9fd6426 100644 --- a/cmdline/elem.h +++ b/cmdline/elem.h @@ -409,6 +409,7 @@ struct snapraid_parity { block_off_t total_blocks; /**< Number of total blocks. */ block_off_t free_blocks; /**< Number of free blocks at the last sync. */ int skip_access; /**< If the disk is unaccessible and it should be skipped. */ + int is_excluded; /**< If the parity is excluded by disk filter. */ /** * Cumulative time used for parity disks. diff --git a/cmdline/snapraid.c b/cmdline/snapraid.c index 554a09c3..5f88ec4a 100644 --- a/cmdline/snapraid.c +++ b/cmdline/snapraid.c @@ -885,6 +885,15 @@ int main(int argc, char* argv[]) } } + /* errors must be always fixed on all disks */ + /* becasue we don't keep the information on what disk is the error */ + if (filter_error != 0 && !tommy_list_empty(&filterlist_disk)) { + /* LCOV_EXCL_START */ + log_fatal("You cannot use -e, --filter-error and -d, --filter-disk at the same time\n"); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + switch (operation) { case OPERATION_CHECK : case OPERATION_FIX : diff --git a/cmdline/state.c b/cmdline/state.c index b94de4b0..87778f5c 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -135,6 +135,7 @@ void state_init(struct snapraid_state* state) state->parity[l].free_blocks = 0; state->parity[l].tick = 0; state->parity[l].skip_access = 0; + state->parity[l].is_excluded = 0; } state->tick_io = 0; state->tick_cpu = 0; @@ -437,10 +438,16 @@ static void state_config_check(struct snapraid_state* state, const char* path, t break; } if (j == 0) { - /* LCOV_EXCL_START */ - log_fatal("Option -d, --filter-disk %s doesn't match any disk.\n", filter->pattern); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ + /* check matching with parity disks */ + for (l = 0; l < state->level; ++l) + if (fnmatch(filter->pattern, lev_config_name(l), FNM_CASEINSENSITIVE_FOR_WIN) == 0) + break; + if (l == state->level) { + /* LCOV_EXCL_START */ + log_fatal("Option -d, --filter-disk %s doesn't match any data or parity disk.\n", filter->pattern); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } } } } @@ -3234,6 +3241,7 @@ void state_skip(struct snapraid_state* state) void state_filter(struct snapraid_state* state, tommy_list* filterlist_file, tommy_list* filterlist_disk, int filter_missing, int filter_error) { tommy_node* i; + unsigned l; /* if no filter, include all */ if (!filter_missing && !filter_error && tommy_list_empty(filterlist_file) && tommy_list_empty(filterlist_disk)) @@ -3300,6 +3308,26 @@ void state_filter(struct snapraid_state* state, tommy_list* filterlist_file, tom } } } + + /* if we are filtering by disk */ + if (!tommy_list_empty(filterlist_disk)) { + /* for each parity disk */ + for (l = 0; l < state->level; ++l) { + /* check if the parity is excluded by name */ + if (filter_path(filterlist_disk, 0, lev_config_name(l), 0) != 0) { + /* excluded the parity from further operation */ + state->parity[l].is_excluded = 1; + } + } + } else { + /* if we are filtering by file, exclude all parity */ + if (filter_missing || !tommy_list_empty(filterlist_file)) { + /* for each parity disk */ + for (l = 0; l < state->level; ++l) { + state->parity[l].is_excluded = 1; + } + } + } } int state_progress_begin(struct snapraid_state* state, block_off_t blockstart, block_off_t blockmax, block_off_t countmax) diff --git a/snapraid.1 b/snapraid.1 index a293aff7..4d467ae6 100644 --- a/snapraid.1 +++ b/snapraid.1 @@ -956,6 +956,8 @@ In \[dq]check\[dq], you can make it faster, specifying also \-a, \-\-audit\-only option, to avoid to access other disks to check parity data. If you combine more \-\-filter, \-\-filter\-disk and \-\-filter\-missing options, only files matching all the set of filters are selected. +You can also specify parity disks with the names: \[dq]parity\[dq], \[dq]2\-parity\[dq], +\[dq]3\-parity\[dq], ... to limit the operations a specific parity disk. This option can be used many times. This option can be used only with \[dq]check\[dq] and \[dq]fix\[dq]. Note that it cannot be used with \[dq]sync\[dq] and \[dq]scrub\[dq], because they always diff --git a/snapraid.d b/snapraid.d index 78d677b4..0c19397d 100644 --- a/snapraid.d +++ b/snapraid.d @@ -670,6 +670,8 @@ Options option, to avoid to access other disks to check parity data. If you combine more --filter, --filter-disk and --filter-missing options, only files matching all the set of filters are selected. + You can also specify parity disks with the names: "parity", "2-parity", + "3-parity", ... to limit the operations a specific parity disk. This option can be used many times. This option can be used only with "check" and "fix". Note that it cannot be used with "sync" and "scrub", because they always diff --git a/snapraid.txt b/snapraid.txt index 2dde37b7..654fc87c 100644 --- a/snapraid.txt +++ b/snapraid.txt @@ -729,6 +729,8 @@ SnapRAID provides the following options: option, to avoid to access other disks to check parity data. If you combine more --filter, --filter-disk and --filter-missing options, only files matching all the set of filters are selected. + You can also specify parity disks with the names: "parity", "2-parity", + "3-parity", ... to limit the operations a specific parity disk. This option can be used many times. This option can be used only with "check" and "fix". Note that it cannot be used with "sync" and "scrub", because they always