From 4adef9dc175714adbabded620dad946c4c99e096 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Sat, 1 Oct 2011 19:18:32 +0200 Subject: [PATCH] Saves the disk mapping inside the content file. --- HISTORY | 8 +- Makefile.am | 25 +++- TODO | 12 +- check.c | 31 ++++- dry.c | 5 +- elem.c | 16 +++ elem.h | 21 +++ handle.c | 44 +++++-- snapraid.1 | 5 +- snapraid.d | 8 +- snapraid.txt | 14 +- state.c | 297 ++++++++++++++++++++++++++++++++----------- state.h | 1 + sync.c | 22 +++- test-raid6-hole.conf | 9 ++ 15 files changed, 399 insertions(+), 119 deletions(-) create mode 100644 test-raid6-hole.conf diff --git a/HISTORY b/HISTORY index b01875be..22e1b2c2 100644 --- a/HISTORY +++ b/HISTORY @@ -1,8 +1,8 @@ SnapRAID HISTORY ================ -1.7 2011/9 -========== +1.7 2011/10 +=========== * If a file is modified or removed during a sync, the sync process doesn't stop anymore, but it will simply skip the file, resulting in an incomplete sync. Note that the sync will terminate with an error. @@ -12,6 +12,10 @@ SnapRAID HISTORY a suggestion, but now it's a requirement in case you put them in data disks. * Added checks to ensure that data and parity disks are diffent, and to correctly count the number of copies of "content" files in different disks. +* Removed the dependency of the 'disk' order specification in the configuration + file. The used order is now saved in the content file to avoid to damage the + dual parity in case the order is changed by the user. + It also allows to remove or add disks from the array when using a dual parity. 1.6 2011/9 - THIS UPDATE IS HIGHLY RECOMMENDED! =============================================== diff --git a/Makefile.am b/Makefile.am index 444c563b..5b4a855c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -55,8 +55,7 @@ EXTRA_DIST = \ noautomake.sh \ README AUTHORS HISTORY INSTALL COPYING TODO TEST \ snapraid.d snapraid.1 snapraid.txt \ - test-raid5.conf \ - test-raid6.conf \ + test-raid5.conf test-raid6.conf test-raid6-hole.conf \ snapraid.conf.example \ configure.windows-x86 configure.windows-x64 snapraid.conf.example.windows \ acinclude.m4 @@ -107,12 +106,30 @@ check-local: $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid5.conf check echo --- Extend raid5 to raid6 with fix and check $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self --test-expect-recoverable -c $(srcdir)/test-raid6.conf check 2>> test.log - $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf fix 2>/dev/null + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf fix 2>> test.log $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid5.conf check $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf check echo --- Dry $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid5.conf dry $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf dry + echo --- Make a hole + mv test/disk2 test/disk2.old + mkdir test/disk2 + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self --force-empty -c $(srcdir)/test-raid6.conf sync + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf check + echo --- Use the with the hole + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6-hole.conf sync + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6-hole.conf check + rm -r test/disk1/_a + rm -r test/disk3/_a + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6-hole.conf fix 2>> test.log + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6-hole.conf check + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6-hole.conf dry + echo --- Fill the hole + rm -r test/disk2 + mv test/disk2.old test/disk2 + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf sync + $(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) --test-skip-self -c $(srcdir)/test-raid6.conf check echo --- Delete some files, create some new, sync and check rm test/disk1/1* rm test/disk2/2* @@ -282,7 +299,7 @@ check-local: # Manual testing -MANUAL = ./snapraid --test-skip-self -c test-raid5.conf sync +MANUAL = ./snapraid --test-skip-self --test-skip-device -c test-raid5.conf sync valgrind: valgrind \ diff --git a/TODO b/TODO index a7d26140..6cdf723c 100644 --- a/TODO +++ b/TODO @@ -5,13 +5,7 @@ This is the list of TODO items for SnapRAID. - v1.7 -* Put the content files in the data disks in the default configuration file. - -* Remove the dependency of the 'disk' order specification in the conf file. -The used order can be defined by SnapRAID and saved in the content file to avoid -to damage the parity in case the order is changed by the user. -It will also allow to remove disks from the array when using a dual parity -configuration, as it's always possible to keep internally dummy empty disks. +* When scanning, ensure that each file is in the expected disk. * When fixing, before overwriting the present file, make a copy of it just in case that the original file cannot be completely recovered. @@ -21,6 +15,10 @@ The same for symlink if a file with the same name exist or viceversa. - v1.8 +* Check why saving the content files is so slow. fprintf() is the bottleneck. + +* Put the content files in the data disks in the default configuration file. + * Easy way to find duplicates using the computed hash. * Easy way to find files using a specified block. diff --git a/check.c b/check.c index 5a69a372..203ef90a 100644 --- a/check.c +++ b/check.c @@ -63,7 +63,7 @@ static int blockcmp(struct snapraid_state* state, struct snapraid_block* block, /** * Repair errors. - * Returns <0 if failure for missing stratey, >0 if data is wrong and we cannot rebuild correctly, 0 on success. + * Returns <0 if failure for missing strategy, >0 if data is wrong and we cannot rebuild correctly, 0 on success. * If success, the parity and qarity are computed in the buffer variable. */ static int repair(struct snapraid_state* state, unsigned i, unsigned diskmax, struct failed_struct* failed, unsigned failed_count, unsigned char** buffer, unsigned char* buffer_parity, unsigned char* buffer_qarity, unsigned char* buffer_zero) @@ -73,7 +73,7 @@ static int repair(struct snapraid_state* state, unsigned i, unsigned diskmax, st /* no fix required */ if (failed_count == 0) { - /* compute parity and qarity to check it */ + /* recompute only parity and qarity */ raid_gen(state->level, buffer, diskmax, state->block_size); return 0; } @@ -199,7 +199,9 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity /* for each disk */ one_tocheck = 0; for(j=0;jblock_size); + continue; + } + + /* if the disk block is not used */ block = disk_block_get(handle[j].disk, i); if (!block) { /* use an empty block */ @@ -524,11 +536,12 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity if (fix) { /* for all the files of this block check if we need to fix the modification time */ for(j=0;jlinklist; while (node) { char path[PATH_MAX]; diff --git a/dry.c b/dry.c index 7cba59f6..b4427523 100644 --- a/dry.c +++ b/dry.c @@ -53,9 +53,10 @@ static int state_dry_process(struct snapraid_state* state, int parity_f, int qar /* for each disk, process the block */ for(j=0;jname, sizeof(map->name), name); + map->position = position; + + return map; +} + +void map_free(struct snapraid_map* map) +{ + free(map); +} + diff --git a/elem.h b/elem.h index adf22d99..0b5b5f7e 100644 --- a/elem.h +++ b/elem.h @@ -133,6 +133,17 @@ struct snapraid_disk { tommy_node node; }; +/** + * Disk mapping. + */ +struct snapraid_map { + char name[PATH_MAX]; /**< Name of the disk. */ + unsigned position; /**< Position of the disk in the parity. */ + + /* nodes for data structures */ + tommy_node node; +}; + /** * Allocates a content. */ @@ -323,5 +334,15 @@ static inline struct snapraid_block* disk_block_get(struct snapraid_disk* disk, return 0; } +/** + * Allocates a disk mapping. + */ +struct snapraid_map* map_alloc(const char* name, unsigned position); + +/** + * Deallocates a disk mapping. + */ +void map_free(struct snapraid_map* map); + #endif diff --git a/handle.c b/handle.c index 90fb1393..9a69fb12 100644 --- a/handle.c +++ b/handle.c @@ -327,21 +327,49 @@ struct snapraid_handle* handle_map(struct snapraid_state* state, unsigned* handl { tommy_node* i; unsigned j; + unsigned size = 0; struct snapraid_handle* handle; - /* first count the disks */ - *handlemax = 0; - for(i=state->disklist;i!=0;i=i->next) - ++*handlemax; + /* get the size of the mapping */ + size = 0; + for(i=state->maplist;i!=0;i=i->next) { + struct snapraid_map* map = i->data; + if (map->position > size) + size = map->position; + } + ++size; /* size is one more than the max */ - handle = malloc_nofail(*handlemax * sizeof(struct snapraid_handle)); + handle = malloc_nofail(size * sizeof(struct snapraid_handle)); - /* set the vector */ - for(i=state->disklist,j=0;i!=0;i=i->next,++j) { - handle[j].disk = i->data; + for(j=0;jdisklist;i!=0;i=i->next) { + struct snapraid_map* map; + struct snapraid_disk* disk = i->data; + tommy_node* k; + + /* search the mapping for this disk */ + for(k=state->maplist;k!=0;k=k->next) { + map = k->data; + if (strcmp(disk->name, map->name) == 0) + break; + } + if (k==0) { + fprintf(stderr, "Inconsistent disk mapping.\n"); + exit(EXIT_FAILURE); + continue; + } + + handle[map->position].disk = disk; + } + + *handlemax = size; return handle; } + diff --git a/snapraid.1 b/snapraid.1 index ab543285..f3c17ed7 100644 --- a/snapraid.1 +++ b/snapraid.1 @@ -421,9 +421,6 @@ DIR is the mount point of the disk in the filesystem. You can change the mount point as you like, as long you keep the NAME fixed. .PP -The specification order is also important, if you change it, -you will invalidate the q\(hyparity file. -.PP You should use one option for each disk of the array. .SS exclude/include PATTERN Defines the file or directory patterns to exclude and include @@ -717,6 +714,8 @@ Defines the size of the block in bytes. It must match the size defined in the configuration file. .SS checksum CHECKSUM Defines the checksum kind used. It can be \(a"md5\(a" or \(a"murmur3\(a". +.SS map NAME INDEX +Defines the position INDEX of the disk NAME in the parity computation. .SS file DISK SIZE TIME INODE PATH Defines a file in the specified DISK. .PP diff --git a/snapraid.d b/snapraid.d index ce42b43c..d9462c62 100644 --- a/snapraid.d +++ b/snapraid.d @@ -319,9 +319,6 @@ Configuration You can change the mount point as you like, as long you keep the NAME fixed. - The specification order is also important, if you change it, - you will invalidate the q-parity file. - You should use one option for each disk of the array. exclude/include PATTERN @@ -488,13 +485,16 @@ Content checksum CHECKSUM Defines the checksum kind used. It can be "md5" or "murmur3". + map NAME INDEX + Defines the position INDEX of the disk NAME in the parity computation. + file DISK SIZE TIME INODE PATH Defines a file in the specified DISK. The INODE number is used to identify the file in the "sync" command, allowing to rename or move the file in disk without the need to recompute the parity for it. - + The SIZE and TIME information are used to identify if the file changed from the last "sync" command, and if there is the need to recompute the parity. diff --git a/snapraid.txt b/snapraid.txt index 1e9e1a4b..5ad108d2 100644 --- a/snapraid.txt +++ b/snapraid.txt @@ -357,9 +357,6 @@ DIR is the mount point of the disk in the filesystem. You can change the mount point as you like, as long you keep the NAME fixed. -The specification order is also important, if you change it, -you will invalidate the q-parity file. - You should use one option for each disk of the array. 7.5 exclude/include PATTERN @@ -542,7 +539,12 @@ defined in the configuration file. Defines the checksum kind used. It can be "md5" or "murmur3". -9.3 file DISK SIZE TIME INODE PATH +9.3 map NAME INDEX +------------------ + +Defines the position INDEX of the disk NAME in the parity computation. + +9.4 file DISK SIZE TIME INODE PATH ---------------------------------- Defines a file in the specified DISK. @@ -558,7 +560,7 @@ to recompute the parity. The PATH information is used in the "check" and "fix" commands to identify the file. -9.4 blk BLOCK HASH +9.5 blk BLOCK HASH ------------------ Defines the ordered parity block list used by the last defined file. @@ -569,7 +571,7 @@ BLOCK is the block position in the "parity" file. HASH is the hash of the block. In the last block of the file, the HASH is the hash of only the used part of the block. -9.5 inv BLOCK [HASH] +9.6 inv BLOCK [HASH] -------------------- Like "blk", but inform that the parity of this block is invalid. diff --git a/state.c b/state.c index b5795ae7..ec23ad75 100644 --- a/state.c +++ b/state.c @@ -38,6 +38,7 @@ void state_init(struct snapraid_state* state) state->level = 1; /* default is the lowest protection */ state->hash = HASH_MURMUR3; /* default is the fastest */ tommy_list_init(&state->disklist); + tommy_list_init(&state->maplist); tommy_list_init(&state->contentlist); tommy_list_init(&state->filterlist); } @@ -45,10 +46,89 @@ void state_init(struct snapraid_state* state) void state_done(struct snapraid_state* state) { tommy_list_foreach(&state->disklist, (tommy_foreach_func*)disk_free); + tommy_list_foreach(&state->maplist, (tommy_foreach_func*)map_free); tommy_list_foreach(&state->contentlist, (tommy_foreach_func*)content_free); tommy_list_foreach(&state->filterlist, (tommy_foreach_func*)filter_free); } +/** + * Checks the configuration. + */ +static void state_config_check(struct snapraid_state* state, const char* path, int skip_device) +{ + if (state->parity[0] == 0) { + fprintf(stderr, "No 'parity' specification in '%s'\n", path); + exit(EXIT_FAILURE); + } + + if (tommy_list_empty(&state->contentlist)) { + fprintf(stderr, "No 'content' specification in '%s'\n", path); + exit(EXIT_FAILURE); + } + + /* count the content files */ + if (!skip_device) { + unsigned content_count; + tommy_node* i; + + content_count = 0; + for(i=state->contentlist;i!=0;i=i->next) { + tommy_node* j; + struct snapraid_content* content = i->data; + + /* check if there are others in the same disk */ + for(j=i->next;j!=0;j=j->next) { + struct snapraid_content* other = j->data; + if (content->device == other->device) { + break; + } + } + if (j != 0) { + /* skip it */ + continue; + } + + ++content_count; + } + + if (content_count < state->level+1) { + fprintf(stderr, "You must have at least %d 'content' files in different disks.\n", state->level+1); + exit(EXIT_FAILURE); + } + } + + /* check if all the data and parity disks are different */ + if (!skip_device) { + tommy_node* i; + for(i=state->disklist;i!=0;i=i->next) { + tommy_node* j; + struct snapraid_disk* disk = i->data; + + for(j=i->next;j!=0;j=j->next) { + struct snapraid_disk* other = j->data; + if (disk->device == other->device) { + fprintf(stderr, "Disks '%s' and '%s' are on the same device.\n", disk->dir, other->dir); + exit(EXIT_FAILURE); + } + } + + if (disk->device == state->parity_device) { + fprintf(stderr, "Disk '%s' and parity '%s' are on the same device.\n", disk->dir, state->parity); + exit(EXIT_FAILURE); + } + + if (disk->device == state->qarity_device) { + fprintf(stderr, "Disk '%s' and parity '%s' are on the same device.\n", disk->dir, state->qarity); + exit(EXIT_FAILURE); + } + } + if (state->parity_device == state->qarity_device) { + fprintf(stderr, "Parity '%s' and '%s' are on the same device.\n", state->parity, state->qarity); + exit(EXIT_FAILURE); + } + } +} + void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int expect_unrecoverable, int expect_recoverable, int skip_device) { STREAM* f; @@ -306,77 +386,7 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i sclose(f); - if (state->parity[0] == 0) { - fprintf(stderr, "No 'parity' specification in '%s'\n", path); - exit(EXIT_FAILURE); - } - - if (tommy_list_empty(&state->contentlist)) { - fprintf(stderr, "No 'content' specification in '%s'\n", path); - exit(EXIT_FAILURE); - } - - /* count the content files */ - if (!skip_device) { - unsigned content_count; - tommy_node* i; - - content_count = 0; - for(i=state->contentlist;i!=0;i=i->next) { - tommy_node* j; - struct snapraid_content* content = i->data; - - /* check if there are others in the same disk */ - for(j=i->next;j!=0;j=j->next) { - struct snapraid_content* other = j->data; - if (content->device == other->device) { - break; - } - } - if (j != 0) { - /* skip it */ - continue; - } - - ++content_count; - } - - if (content_count < state->level+1) { - fprintf(stderr, "You must have at least %d 'content' files in different disks.\n", state->level+1); - exit(EXIT_FAILURE); - } - } - - /* check if all the data and parity disks are different */ - if (!skip_device) { - tommy_node* i; - for(i=state->disklist;i!=0;i=i->next) { - tommy_node* j; - struct snapraid_disk* disk = i->data; - - for(j=i->next;j!=0;j=j->next) { - struct snapraid_disk* other = j->data; - if (disk->device == other->device) { - fprintf(stderr, "Disks '%s' and '%s' are on the same device.\n", disk->dir, other->dir); - exit(EXIT_FAILURE); - } - } - - if (disk->device == state->parity_device) { - fprintf(stderr, "Disk '%s' and parity '%s' are on the same device.\n", disk->dir, state->parity); - exit(EXIT_FAILURE); - } - - if (disk->device == state->qarity_device) { - fprintf(stderr, "Disk '%s' and parity '%s' are on the same device.\n", disk->dir, state->qarity); - exit(EXIT_FAILURE); - } - } - if (state->parity_device == state->qarity_device) { - fprintf(stderr, "Parity '%s' and '%s' are on the same device.\n", state->parity, state->qarity); - exit(EXIT_FAILURE); - } - } + state_config_check(state, path, skip_device); if (state->gui) { tommy_node* i; @@ -396,6 +406,108 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i } } +/** + * Updates the disk mapping if required. + */ +static void state_map(struct snapraid_state* state) +{ + unsigned hole; + tommy_node* i; + + /* removes all the mapping without a disk */ + /* this happens when a disk is removed from the configuration file */ + for(i=state->maplist;i!=0;) { + struct snapraid_map* map = i->data; + struct snapraid_disk* disk; + tommy_node* j; + + for(j=state->disklist;j!=0;j=j->next) { + disk = j->data; + if (strcmp(disk->name, map->name) == 0) { + /* disk found */ + break; + } + } + + /* go to the next mapping before removing */ + i = i->next; + + if (j==0) { + /* disk not found, remove the mapping */ + tommy_list_remove_existing(&state->maplist, &map->node); + map_free(map); + } + } + + /* maps each unmapped disk present in the configuration file in the first available hole */ + /* this happens when you add disks for the first time in the configuration file */ + hole = 0; /* first position to try */ + for(i=state->disklist;i!=0;i=i->next) { + struct snapraid_disk* disk = i->data; + struct snapraid_map* map; + tommy_node* j; + + /* check if the disk is already mapped */ + for(j=state->maplist;j!=0;j=j->next) { + map = j->data; + if (strcmp(disk->name, map->name) == 0) { + /* mapping found */ + break; + } + } + if (j!=0) + continue; + + /* mapping not found, search for an hole */ + while (1) { + for(j=state->maplist;j!=0;j=j->next) { + map = j->data; + if (map->position == hole) { + /* position already used */ + break; + } + } + if (j==0) { + /* hole found */ + break; + } + + /* try with the next one */ + ++hole; + } + + /* insert the new mapping */ + map = map_alloc(disk->name, hole); + + tommy_list_insert_tail(&state->maplist, &map->node, map); + } +} + +/** + * Checks the content. + */ +static void state_content_check(struct snapraid_state* state, const char* path) +{ + tommy_node* i; + + /* checks that any map has different name and position */ + for(i=state->maplist;i!=0;i=i->next) { + struct snapraid_map* map = i->data; + tommy_node* j; + for(j=i->next;j!=0;j=j->next) { + struct snapraid_map* other = j->data; + if (strcmp(map->name, other->name) == 0) { + fprintf(stderr, "Colliding 'map' disk specification in '%s'\n", path); + exit(EXIT_FAILURE); + } + if (map->position == other->position) { + fprintf(stderr, "Colliding 'map' index specification in '%s'\n", path); + exit(EXIT_FAILURE); + } + } + } +} + void state_read(struct snapraid_state* state) { STREAM* f; @@ -448,6 +560,9 @@ void state_read(struct snapraid_state* state) /* if not found, assume empty */ if (!f) { + /* create the initial mapping */ + state_map(state); + fprintf(stderr, "No content file found. Assuming empty.\n"); return; } @@ -764,6 +879,31 @@ void state_read(struct snapraid_state* state) fprintf(stderr, "Please restore the 'block_size' value in the configuration file to '%u'\n", blksize / 1024); exit(EXIT_FAILURE); } + } else if (strcmp(tag, "map") == 0) { + struct snapraid_map* map; + uint32_t v_pos; + + ret = sgettok(f, buffer, sizeof(buffer)); + if (ret < 0) { + fprintf(stderr, "Invalid 'map' specification in '%s' at line %u\n", path, line); + exit(EXIT_FAILURE); + } + + c = sgetc(f); + if (c != ' ') { + fprintf(stderr, "Invalid 'map' specification in '%s' at line %u\n", path, line); + exit(EXIT_FAILURE); + } + + ret = sgetu32(f, &v_pos); + if (ret < 0) { + fprintf(stderr, "Invalid 'map' specification in '%s' at line %u\n", path, line); + exit(EXIT_FAILURE); + } + + map = map_alloc(buffer, v_pos); + + tommy_list_insert_tail(&state->maplist, &map->node, map); } else if (tag[0] == 0) { /* allow empty lines */ sgetspace(f); @@ -802,6 +942,11 @@ void state_read(struct snapraid_state* state) sclose(f); + /* update the mapping */ + state_map(state); + + state_content_check(state, path); + if (state->verbose) { printf("\tfile %u\n", count_file); printf("\tblock %u\n", count_block); @@ -848,6 +993,16 @@ static void state_write_one(struct snapraid_state* state, const char* path, unsi exit(EXIT_FAILURE); } + /* for each map */ + for(i=state->maplist;i!=0;i=i->next) { + struct snapraid_map* map = i->data; + ret = fprintf(f, "map %s %u\n", map->name, map->position); + if (ret < 0) { + fprintf(stderr, "Error writing the content file '%s' in fprintf(). %s.\n", tmp, strerror(errno)); + exit(EXIT_FAILURE); + } + } + /* for each disk */ for(i=state->disklist;i!=0;i=i->next) { tommy_node* j; diff --git a/state.h b/state.h index 33032341..ed2bd77c 100644 --- a/state.h +++ b/state.h @@ -46,6 +46,7 @@ struct snapraid_state { unsigned hash; /**< Hash kind used. */ tommy_list contentlist; /**< List of content files. */ tommy_list disklist; /**< List of all the disks. */ + tommy_list maplist; /**< List of all the disk mappings. */ tommy_list filterlist; /**< List of inclusion/exclusion. */ time_t progress_start; /**< Start of processing for progress visualization. */ time_t progress_last; /**< Last update of progress visualization. */ diff --git a/sync.c b/sync.c index f8500ca6..7f6cab6e 100644 --- a/sync.c +++ b/sync.c @@ -65,7 +65,9 @@ static int state_sync_process(struct snapraid_state* state, int parity_f, int qa /* for each disk */ one_invalid = 0; for(j=0;jblock_size); + continue; + } + + /* if the disk block is not used */ block = disk_block_get(handle[j].disk, i); if (!block) { /* use an empty block */ @@ -233,9 +245,9 @@ static int state_sync_process(struct snapraid_state* state, int parity_f, int qa /* for each disk, mark the blocks as processed */ for(j=0;j