Saves the disk mapping inside the content file.

This commit is contained in:
Andrea Mazzoleni 2011-10-01 19:18:32 +02:00
parent 99515f610c
commit 4adef9dc17
15 changed files with 399 additions and 119 deletions

View file

@ -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!
===============================================

View file

@ -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 \

12
TODO
View file

@ -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.

31
check.c
View file

@ -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;j<diskmax;++j) {
struct snapraid_block* block = disk_block_get(handle[j].disk, i);
struct snapraid_block* block = 0;
if (handle[j].disk)
block = disk_block_get(handle[j].disk, i);
if (block
&& block_flag_has(block, BLOCK_HAS_HASH) /* only if the block is hashed */
&& !file_flag_has(block_file_get(block), FILE_IS_EXCLUDED) /* only if the file is not filtered out */
@ -231,7 +233,9 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
/* for each disk */
one_tocheck = 0;
for(j=0;j<diskmax;++j) {
struct snapraid_block* block = disk_block_get(handle[j].disk, i);
struct snapraid_block* block = 0;
if (handle[j].disk)
block = disk_block_get(handle[j].disk, i);
if (block
&& block_flag_has(block, BLOCK_HAS_HASH) /* only if the block is hashed */
&& !file_flag_has(block_file_get(block), FILE_IS_EXCLUDED) /* only if the file is not filtered out */
@ -254,6 +258,14 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
unsigned char hash[HASH_SIZE];
struct snapraid_block* block;
/* if the disk position is not used */
if (!handle[j].disk) {
/* use an empty block */
memset(buffer[j], 0, state->block_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;j<diskmax;++j) {
struct snapraid_block* block;
struct snapraid_block* block = 0;
struct snapraid_file* collide_file;
uint64_t inode;
block = disk_block_get(handle[j].disk, i);
if (handle[j].disk)
block = disk_block_get(handle[j].disk, i);
if (!block) {
/* if no block, no file and nothing to do */
continue;
@ -593,9 +606,13 @@ static int state_check_process(struct snapraid_state* state, int fix, int parity
/* check all the links */
for(i=0;i<diskmax;++i) {
tommy_node* node;
struct snapraid_disk* disk = handle[i].disk;
struct snapraid_disk* disk;
if (!handle[i].disk)
continue;
/* for each link in the disk */
disk = handle[i].disk;
node = disk->linklist;
while (node) {
char path[PATH_MAX];

5
dry.c
View file

@ -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;j<diskmax;++j) {
int read_size;
struct snapraid_block* block;
struct snapraid_block* block = 0;
block = disk_block_get(handle[j].disk, i);
if (handle[j].disk)
block = disk_block_get(handle[j].disk, i);
if (!block)
continue;

16
elem.c
View file

@ -363,3 +363,19 @@ void disk_free(struct snapraid_disk* disk)
free(disk);
}
struct snapraid_map* map_alloc(const char* name, unsigned position)
{
struct snapraid_map* map;
map = malloc_nofail(sizeof(struct snapraid_map));
pathcpy(map->name, sizeof(map->name), name);
map->position = position;
return map;
}
void map_free(struct snapraid_map* map)
{
free(map);
}

21
elem.h
View file

@ -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

View file

@ -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;j<size;++j) {
/* default for empty position */
handle[j].disk = 0;
handle[j].file = 0;
handle[j].f = -1;
}
/* set the vector */
for(i=state->disklist;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;
}

View file

@ -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

View file

@ -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.

View file

@ -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.

297
state.c
View file

@ -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;

View file

@ -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. */

22
sync.c
View file

@ -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;j<diskmax;++j) {
struct snapraid_block* block = disk_block_get(handle[j].disk, i);
struct snapraid_block* block = 0;
if (handle[j].disk)
block = disk_block_get(handle[j].disk, i);
if (block && !block_flag_has(block, BLOCK_HAS_HASH | BLOCK_HAS_PARITY)) {
one_invalid = 1;
break;
@ -90,7 +92,9 @@ static int state_sync_process(struct snapraid_state* state, int parity_f, int qa
/* for each disk */
one_invalid = 0;
for(j=0;j<diskmax;++j) {
struct snapraid_block* block = disk_block_get(handle[j].disk, i);
struct snapraid_block* block = 0;
if (handle[j].disk)
block = disk_block_get(handle[j].disk, i);
if (block && !block_flag_has(block, BLOCK_HAS_HASH | BLOCK_HAS_PARITY)) {
one_invalid = 1;
break;
@ -110,6 +114,14 @@ static int state_sync_process(struct snapraid_state* state, int parity_f, int qa
unsigned char hash[HASH_SIZE];
struct snapraid_block* block;
/* if the disk position is not used */
if (!handle[j].disk) {
/* use an empty block */
memset(buffer[j], 0, state->block_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<diskmax;++j) {
struct snapraid_block* block;
block = disk_block_get(handle[j].disk, i);
struct snapraid_block* block = 0;
if (handle[j].disk)
block = disk_block_get(handle[j].disk, i);
if (!block)
continue;

9
test-raid6-hole.conf Normal file
View file

@ -0,0 +1,9 @@
block_size 1
parity test/parity
q-parity test/q-parity
content test/content
content test/p-content
content test/q-content
disk d1 test/disk1/
disk d3 test/disk3/