From 99420cffab106c726e19e070aedee47ff2180db6 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Mon, 25 Apr 2011 13:43:51 +0200 Subject: [PATCH] Allow to specify multiple content files. --- HISTORY | 5 +-- elem.c | 15 ++++++++ elem.h | 18 ++++++++++ snapraid.1 | 69 +++++++++++++++++++++++------------ snapraid.conf.example | 23 ++++++++---- snapraid.d | 61 +++++++++++++++++++------------ snapraid.txt | 61 +++++++++++++++++++------------ state.c | 84 ++++++++++++++++++++++++++++--------------- state.h | 2 +- test-raid6.conf | 1 + 10 files changed, 232 insertions(+), 107 deletions(-) diff --git a/HISTORY b/HISTORY index b1c16cc6..9081c73f 100644 --- a/HISTORY +++ b/HISTORY @@ -4,10 +4,11 @@ SnapRAID HISTORY 1.1 2011/5 ========== * Added RAID6 support. -* The default checksum is Murmur3 hash. +* Allow to specify multiple content files. +* Changed the default checksum to Murmur3 hash. It's a lot faster than MD5. MD5 is still supported for backward compatibility. * The check command returns with an error code if any kind of error is present. - Previously it was only if unrecoverable error was present. + Previously it was only if unrecoverable errors were present. 1.0 2011/4 ========== diff --git a/elem.c b/elem.c index f11cbf51..5601a396 100644 --- a/elem.c +++ b/elem.c @@ -23,6 +23,21 @@ /****************************************************************************/ /* snapraid */ +struct snapraid_content* content_alloc(const char* path) +{ + struct snapraid_content* content; + + content = malloc_nofail(sizeof(struct snapraid_content)); + pathcpy(content->content, sizeof(content->content), path); + + return content; +} + +void content_free(struct snapraid_content* content) +{ + free(content); +} + struct snapraid_filter* filter_alloc(const char* pattern) { struct snapraid_filter* filter; diff --git a/elem.h b/elem.h index 21b210a3..3182d661 100644 --- a/elem.h +++ b/elem.h @@ -44,6 +44,14 @@ typedef uint32_t block_off_t; */ typedef int64_t data_off_t; +/** + * Content file specification. + */ +struct snapraid_content { + char content[PATH_MAX]; /**< Path of the content file. */ + tommy_node node; /**< Next node in the list. */ +}; + /** * Filter for paths. */ @@ -99,6 +107,16 @@ struct snapraid_disk { tommy_array blockarr; /**< Block array of the disk. */ }; +/** + * Allocates a content. + */ +struct snapraid_content* content_alloc(const char* path); + +/** + * Deallocates a content. + */ +void content_free(struct snapraid_content* content); + /** * Allocates an exclusion. */ diff --git a/snapraid.1 b/snapraid.1 index 6e8e5024..b426517a 100644 --- a/snapraid.1 +++ b/snapraid.1 @@ -109,21 +109,23 @@ hard\(hylinks, symbolic\(hylinks are not saved. .PD .SH GETTING STARTED To use SnapRAID you need first select one disk of your disk array -to dedicate at the parity information. With parity you will be able -to recover from a single disk failure. +to dedicate at the \(a"parity\(a" information. With parity you will be able +to recover from a single disk failure, like RAID5. .PP -If you want to recover from two disk failures you must reserve -another disk for the q\(hyparity information. +If you want to recover from two disk failures, like RAID6, you must +reserve another disk for the \(a"q\(hyparity\(a" information .PP For both disks, you have to pick the biggest disks in the array, as the redundancy information may grow in size as the biggest data disk in the array. .PP -This disk will be dedicated to store the parity and q\(hyparity. -You should not store other data on it, with the exception of -the content metadata information. +This disk will be dedicated to store the \(a"parity\(a" and \(a"q\(hyparity\(a" +files. +You should not store other data on them, with the exception of +a copy the \(a"content\(a" file, that contains the list of all the files +stored in your array with all the checksums to verify their integrity. .PP -For example, suppose that you are interested only at the parity level +For example, suppose that you are interested only at one parity level of protection, and that all your disks are present in: .PP .RS 4 @@ -215,7 +217,7 @@ will start where interrupted. .PP When this command completes, your data is SAFE. .PP -At this point you can start using your data as you like, and periodically +At this point you can start using your array as you like, and periodically update the redundancy information running the \(a"sync\(a" command. .PP To check the integrity of your data you can use the \(a"check\(a" command: @@ -244,7 +246,14 @@ in \(a"sync\(a". .PP In this regard snapraid is more like a backup program than a RAID system. For example, you can use it to recover from an accidentally -deleted directory, simply running the fix command. +deleted directory, simply running the fix command like. +.PP +.RS 4 +snapraid fix \(hyf JUST_DELETED_DIR/ +.PD 0 +.PP +.PD +.RE .SH COMMANDS SnapRAID provides three simple commands that allow to: .PD 0 @@ -341,6 +350,8 @@ it should contains the following options: .TP .B parity FILE Defines the file to use to store the parity information. +The parity enables the protection from a single disk +failure, like RAID5. It must be placed in a disk dedicated for this purpose with as much free space as the biggest disk in the array. Leaving the parity disk reserved for only this file, ensures that @@ -349,8 +360,8 @@ This option is mandatory and it can be used only one time. .TP .B q\(hyparity FILE Defines the file to use to store the q\(hyparity information. -This option is optional, and if present it enables the protection -from two disk failures. +If present, the q\(hyparity enables the protection from two disk +failures, like RAID6. It must be placed in a disk dedicated for this purpose with as much free space as the biggest disk in the array. Leaving the q\(hyparity disk reserved for only this file, ensures that @@ -360,9 +371,13 @@ This option is optional and it can be used only one time. .B content FILE Defines the file to use to store the content of the redundancy organization. -It can be placed in the same disk of the parity file, or better -in another disk, but NOT in a data disk of the array. -This option is mandatory and it can be used only one time. +It can be placed in the same disk of the parity and q\(hyaparity file, +or better in another disk, but NOT in a data disk of the array. +This option is mandatory and it can be used more time to save +more copies of the same files. +It\(cqs suggested to store at least one copy for each parity disk. +One more doesn\(cqt hurt, just in case you lose all the parity disks, +and you still need to check the data integrity. .TP .B disk NAME DIR Defines the name and the mount point of the disks of the array. @@ -370,6 +385,8 @@ NAME is used to identify the disk, and it must be unique. DIR is the mount point of the disk in the file\(hysystem. You can change the mount point as you like, as far you keep the NAME fixed. +The specification order is also important, if you change it, +you will invalidate the q\(hyparity file. You should use one option for each disk of the array. .TP .B exclude PATTERN @@ -426,6 +443,10 @@ content /mnt/diskpar/content .PD 0 .PP .PD +content /var/snapraid/content +.PD 0 +.PP +.PD disk d1 /mnt/disk1/ .PD 0 .PP @@ -531,11 +552,12 @@ snapraid \(hyf \(a"*.mp3\(a" check .PD .RE .SH CONTENT -SnapRAID creates a metadata content file describing the content of -your disk array. +SnapRAID stores the list of your files in the content file. .PP -It\(cqs a text file, listing all the files in your disk array. You do not -need to understand its format, but it\(cqs described here for documentation. +It\(cqs a text file, listing all the files present in your disk array, +with all the checksums to verify their integrity. +You do not need to understand its format, but it\(cqs described here +for documentation. .PP This file is read and written by the \(a"sync\(a" command, and only read by \(a"fix\(a" and \(a"check\(a". @@ -570,12 +592,13 @@ The HASH may be missing if not yet computed. This field is used only when you interrupt manually the \(a"sync\(a" command. .SH PARITY -SnapRAID creates the parity and q\(hyparity files containing the redundancy -information of your disk array. +SnapRAID stores the redundancy information of your array in the parity +and q\(hyparity files. .PP They are binary files, containing the computed redundancy of all the -blocks defined in the \(a"content\(a" file. You do not need to understand its -format, but it\(cqs described here for documentation. +blocks defined in the \(a"content\(a" file. +You do not need to understand its format, but it\(cqs described here +for documentation. .PP These files are read and written by the \(a"sync\(a" and \(a"fix\(a" commands, and only read by \(a"check\(a". diff --git a/snapraid.conf.example b/snapraid.conf.example index 790748f3..0f245bcf 100644 --- a/snapraid.conf.example +++ b/snapraid.conf.example @@ -1,17 +1,28 @@ -# Configuration for snapraid +# Example configuration for snapraid -# Defines the file to use as parity storage -# It must be in an different disk than the data disks +# Defines the file to use as Parity storage +# It must NOT be in a data disk # Format: "parity FILE_PATH" parity /mnt/diskpar/parity +# Defines the file to use as Q-Parity storage +# If specified, it enables a double failures protection like RAID6 +# It must NOT be in a data disk +# Format: "q-parity FILE_PATH" +#q-parity /mnt/diskqar/q-parity + # Defines the file to use as content list +# You can use multiple specification to store more copies of the file +# It's suggested to have at least N+1 copies of the file, where N is the number of parity files. +# It must NOT be in a data disk +# It can be in the disks used for parity storage # Format: "content FILE_PATH" -# It must be in an different disk than the data disks -# It can be in the same disk used for parity storage content /mnt/diskpar/content +#content /mnt/diskqar/content +content /var/snapraid/content # Defines the data disks to use +# The order is relevant for parity, do not change it # Format: "disk DISK_NAME DISK_MOUNT_POINT" disk d1 /mnt/disk1/ disk d2 /mnt/disk2/ @@ -27,7 +38,7 @@ exclude tmp/ exclude /lost+found/ # Defines the block size in kibi bytes (1024 bytes). -# Format: "block_size SIZE_IN_KiB" # Default value is 256 -> 256 kibi bytes -> 262144 bytes +# Format: "block_size SIZE_IN_KiB" block_size 256 diff --git a/snapraid.d b/snapraid.d index 88f1c013..3b2d27af 100644 --- a/snapraid.d +++ b/snapraid.d @@ -74,21 +74,23 @@ Limitations Getting Started To use SnapRAID you need first select one disk of your disk array - to dedicate at the parity information. With parity you will be able - to recover from a single disk failure. + to dedicate at the "parity" information. With parity you will be able + to recover from a single disk failure, like RAID5. - If you want to recover from two disk failures you must reserve - another disk for the q-parity information. + If you want to recover from two disk failures, like RAID6, you must + reserve another disk for the "q-parity" information For both disks, you have to pick the biggest disks in the array, as the redundancy information may grow in size as the biggest data disk in the array. - This disk will be dedicated to store the parity and q-parity. - You should not store other data on it, with the exception of - the content metadata information. + This disk will be dedicated to store the "parity" and "q-parity" + files. + You should not store other data on them, with the exception of + a copy the "content" file, that contains the list of all the files + stored in your array with all the checksums to verify their integrity. - For example, suppose that you are interested only at the parity level + For example, suppose that you are interested only at one parity level of protection, and that all your disks are present in: :/mnt/diskpar <- selected disk for parity @@ -127,7 +129,7 @@ Getting Started When this command completes, your data is SAFE. - At this point you can start using your data as you like, and periodically + At this point you can start using your array as you like, and periodically update the redundancy information running the "sync" command. To check the integrity of your data you can use the "check" command: @@ -146,7 +148,9 @@ Getting Started In this regard snapraid is more like a backup program than a RAID system. For example, you can use it to recover from an accidentally - deleted directory, simply running the fix command. + deleted directory, simply running the fix command like. + + :snapraid fix -f JUST_DELETED_DIR/ Commands SnapRAID provides three simple commands that allow to: @@ -241,6 +245,8 @@ Configuration =parity FILE Defines the file to use to store the parity information. + The parity enables the protection from a single disk + failure, like RAID5. It must be placed in a disk dedicated for this purpose with as much free space as the biggest disk in the array. Leaving the parity disk reserved for only this file, ensures that @@ -249,8 +255,8 @@ Configuration =q-parity FILE Defines the file to use to store the q-parity information. - This option is optional, and if present it enables the protection - from two disk failures. + If present, the q-parity enables the protection from two disk + failures, like RAID6. It must be placed in a disk dedicated for this purpose with as much free space as the biggest disk in the array. Leaving the q-parity disk reserved for only this file, ensures that @@ -260,9 +266,13 @@ Configuration =content FILE Defines the file to use to store the content of the redundancy organization. - It can be placed in the same disk of the parity file, or better - in another disk, but NOT in a data disk of the array. - This option is mandatory and it can be used only one time. + It can be placed in the same disk of the parity and q-aparity file, + or better in another disk, but NOT in a data disk of the array. + This option is mandatory and it can be used more time to save + more copies of the same files. + It's suggested to store at least one copy for each parity disk. + One more doesn't hurt, just in case you lose all the parity disks, + and you still need to check the data integrity. =disk NAME DIR Defines the name and the mount point of the disks of the array. @@ -270,6 +280,8 @@ Configuration DIR is the mount point of the disk in the file-system. You can change the mount point as you like, as far 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 PATTERN @@ -308,6 +320,7 @@ Configuration :parity /mnt/diskpar/parity :content /mnt/diskpar/content + :content /var/snapraid/content :disk d1 /mnt/disk1/ :disk d2 /mnt/disk2/ :disk d3 /mnt/disk3/ @@ -360,11 +373,12 @@ Pattern :snapraid -f "*.mp3" check Content - SnapRAID creates a metadata content file describing the content of - your disk array. + SnapRAID stores the list of your files in the content file. - It's a text file, listing all the files in your disk array. You do not - need to understand its format, but it's described here for documentation. + It's a text file, listing all the files present in your disk array, + with all the checksums to verify their integrity. + You do not need to understand its format, but it's described here + for documentation. This file is read and written by the "sync" command, and only read by "fix" and "check". @@ -400,12 +414,13 @@ Content command. Parity - SnapRAID creates the parity and q-parity files containing the redundancy - information of your disk array. + SnapRAID stores the redundancy information of your array in the parity + and q-parity files. They are binary files, containing the computed redundancy of all the - blocks defined in the "content" file. You do not need to understand its - format, but it's described here for documentation. + blocks defined in the "content" file. + You do not need to understand its format, but it's described here + for documentation. These files are read and written by the "sync" and "fix" commands, and only read by "check". diff --git a/snapraid.txt b/snapraid.txt index 14b94570..110bcc07 100644 --- a/snapraid.txt +++ b/snapraid.txt @@ -87,21 +87,23 @@ Other limitations are: ================= To use SnapRAID you need first select one disk of your disk array -to dedicate at the parity information. With parity you will be able -to recover from a single disk failure. +to dedicate at the "parity" information. With parity you will be able +to recover from a single disk failure, like RAID5. -If you want to recover from two disk failures you must reserve -another disk for the q-parity information. +If you want to recover from two disk failures, like RAID6, you must +reserve another disk for the "q-parity" information For both disks, you have to pick the biggest disks in the array, as the redundancy information may grow in size as the biggest data disk in the array. -This disk will be dedicated to store the parity and q-parity. -You should not store other data on it, with the exception of -the content metadata information. +This disk will be dedicated to store the "parity" and "q-parity" +files. +You should not store other data on them, with the exception of +a copy the "content" file, that contains the list of all the files +stored in your array with all the checksums to verify their integrity. -For example, suppose that you are interested only at the parity level +For example, suppose that you are interested only at one parity level of protection, and that all your disks are present in: /mnt/diskpar <- selected disk for parity @@ -140,7 +142,7 @@ will start where interrupted. When this command completes, your data is SAFE. -At this point you can start using your data as you like, and periodically +At this point you can start using your array as you like, and periodically update the redundancy information running the "sync" command. To check the integrity of your data you can use the "check" command: @@ -159,7 +161,9 @@ in "sync". In this regard snapraid is more like a backup program than a RAID system. For example, you can use it to recover from an accidentally -deleted directory, simply running the fix command. +deleted directory, simply running the fix command like. + + snapraid fix -f JUST_DELETED_DIR/ 5 COMMANDS @@ -263,6 +267,8 @@ it should contains the following options: parity FILE Defines the file to use to store the parity information. + The parity enables the protection from a single disk + failure, like RAID5. It must be placed in a disk dedicated for this purpose with as much free space as the biggest disk in the array. Leaving the parity disk reserved for only this file, ensures that @@ -271,8 +277,8 @@ it should contains the following options: q-parity FILE Defines the file to use to store the q-parity information. - This option is optional, and if present it enables the protection - from two disk failures. + If present, the q-parity enables the protection from two disk + failures, like RAID6. It must be placed in a disk dedicated for this purpose with as much free space as the biggest disk in the array. Leaving the q-parity disk reserved for only this file, ensures that @@ -282,9 +288,13 @@ it should contains the following options: content FILE Defines the file to use to store the content of the redundancy organization. - It can be placed in the same disk of the parity file, or better - in another disk, but NOT in a data disk of the array. - This option is mandatory and it can be used only one time. + It can be placed in the same disk of the parity and q-aparity file, + or better in another disk, but NOT in a data disk of the array. + This option is mandatory and it can be used more time to save + more copies of the same files. + It's suggested to store at least one copy for each parity disk. + One more doesn't hurt, just in case you lose all the parity disks, + and you still need to check the data integrity. disk NAME DIR Defines the name and the mount point of the disks of the array. @@ -292,6 +302,8 @@ it should contains the following options: DIR is the mount point of the disk in the file-system. You can change the mount point as you like, as far 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 PATTERN @@ -330,6 +342,7 @@ An example of a typical configuration is: parity /mnt/diskpar/parity content /mnt/diskpar/content + content /var/snapraid/content disk d1 /mnt/disk1/ disk d2 /mnt/disk2/ disk d3 /mnt/disk3/ @@ -388,11 +401,12 @@ For example, in the command line: 9 CONTENT ========= -SnapRAID creates a metadata content file describing the content of -your disk array. +SnapRAID stores the list of your files in the content file. -It's a text file, listing all the files in your disk array. You do not -need to understand its format, but it's described here for documentation. +It's a text file, listing all the files present in your disk array, +with all the checksums to verify their integrity. +You do not need to understand its format, but it's described here +for documentation. This file is read and written by the "sync" command, and only read by "fix" and "check". @@ -431,12 +445,13 @@ is described here. 10 PARITY ========= -SnapRAID creates the parity and q-parity files containing the redundancy -information of your disk array. +SnapRAID stores the redundancy information of your array in the parity +and q-parity files. They are binary files, containing the computed redundancy of all the -blocks defined in the "content" file. You do not need to understand its -format, but it's described here for documentation. +blocks defined in the "content" file. +You do not need to understand its format, but it's described here +for documentation. These files are read and written by the "sync" and "fix" commands, and only read by "check". diff --git a/state.c b/state.c index 3d17f594..6a4a2b7a 100644 --- a/state.c +++ b/state.c @@ -35,13 +35,13 @@ void state_init(struct snapraid_state* state) state->expect_recoverable = 0; state->need_write = 0; state->block_size = 256 * 1024; /* default 256 KiB */ - state->content[0] = 0; state->parity[0] = 0; state->qarity[0] = 0; state->level = 1; /* default is the lowest protection */ state->hash = HASH_MURMUR3; /* default is the fastest */ tommy_array_init(&state->diskarr); tommy_list_init(&state->excludelist); + tommy_list_init(&state->contentlist); } void state_done(struct snapraid_state* state) @@ -51,6 +51,7 @@ void state_done(struct snapraid_state* state) for(i=0;idiskarr);++i) disk_free(tommy_array_get(&state->diskarr, i)); tommy_array_done(&state->diskarr); + tommy_list_foreach(&state->contentlist, (tommy_foreach_func*)content_free); tommy_list_foreach(&state->excludelist, (tommy_foreach_func*)filter_free); } @@ -58,6 +59,7 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i { FILE* f; unsigned line; + unsigned content_count; state->verbose = verbose; state->force_zero = force_zero; @@ -78,6 +80,7 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i } line = 0; + content_count = 0; while (1) { char buffer[TEXT_LINE_MAX]; char* tag; @@ -139,11 +142,9 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i pathcpy(state->qarity, sizeof(state->qarity), s); state->level = 2; } else if (strcmp(tag, "content") == 0) { - if (*state->content) { - fprintf(stderr, "Multiple 'content' specification in '%s' at line %u\n", path, line); - exit(EXIT_FAILURE); - } - pathcpy(state->content, sizeof(state->content), s); + struct snapraid_content* content = content_alloc(s); + tommy_list_insert_tail(&state->contentlist, &content->node, content); + ++content_count; } else if (strcmp(tag, "disk") == 0) { char* name = s; s = strtoken(s); @@ -163,12 +164,16 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i fclose(f); - if (!state->parity) { - fprintf(stderr, "No 'parity' specification in '%s' at line %u\n", path, line); + if (state->parity[0] == 0) { + fprintf(stderr, "No 'parity' specification in '%s'\n", path); exit(EXIT_FAILURE); } - if (!state->content) { - fprintf(stderr, "No 'content' specification in '%s' at line %u\n", path, line); + if (content_count == 0) { + fprintf(stderr, "No 'content' specification in '%s'\n", path); + exit(EXIT_FAILURE); + } + if (state->qarity[0] != 0 && content_count < 2) { + fprintf(stderr, "With 'q-parity' you must have at least two 'content' specifications in '%s'\n", path); exit(EXIT_FAILURE); } } @@ -183,12 +188,14 @@ void state_read(struct snapraid_state* state) unsigned line; unsigned count_file; unsigned count_block; + struct snapraid_content* content; count_file = 0; count_block = 0; - pathcpy(path, sizeof(path), state->content); - f = fopen(state->content, "rt"); + content = tommy_list_head(&state->contentlist)->data; + pathcpy(path, sizeof(path), content->content); + f = fopen(path, "rt"); if (!f) { /* if not found, assume empty */ if (errno == ENOENT) @@ -198,7 +205,7 @@ void state_read(struct snapraid_state* state) exit(EXIT_FAILURE); } - printf("Loading state...\n"); + printf("Loading state from %s...\n", path); /* start with a MD5 default. */ /* it's for compatibility with version 1.0 where MD5 was implicit. */ @@ -425,36 +432,36 @@ void state_read(struct snapraid_state* state) } } -void state_write(struct snapraid_state* state) +static void state_write_one(struct snapraid_state* state, const char* path, unsigned* out_count_file, unsigned* out_count_block) { FILE* f; - char path[PATH_MAX]; - unsigned i; + char tmp[PATH_MAX]; unsigned count_file; unsigned count_block; + unsigned i; int ret; count_file = 0; count_block = 0; - printf("Saving state...\n"); + printf("Saving state to %s...\n", path); - pathprint(path, sizeof(path), "%s.tmp", state->content); - f = fopen(path, "wt"); + pathprint(tmp, sizeof(tmp), "%s.tmp", path); + f = fopen(tmp, "wt"); if (!f) { - fprintf(stderr, "Error opening for writing the content file '%s'\n", path); + fprintf(stderr, "Error opening for writing the content file '%s'\n", tmp); exit(EXIT_FAILURE); } ret = fprintf(f, "blksize %u\n", state->block_size); if (ret < 0) { - fprintf(stderr, "Error writing the content file '%s' in fprintf(). %s.\n", path, strerror(errno)); + fprintf(stderr, "Error writing the content file '%s' in fprintf(). %s.\n", tmp, strerror(errno)); exit(EXIT_FAILURE); } ret = fprintf(f, "checksum %s\n", state->hash == HASH_MD5 ? "md5" : "murmur3"); if (ret < 0) { - fprintf(stderr, "Error writing the content file '%s' in fprintf(). %s.\n", path, strerror(errno)); + fprintf(stderr, "Error writing the content file '%s' in fprintf(). %s.\n", tmp, strerror(errno)); exit(EXIT_FAILURE); } @@ -477,7 +484,7 @@ void state_write(struct snapraid_state* state) ret = fprintf(f,"file %s %llu %llu %llu %s\n", disk->name, size, mtime, inode, file->sub); if (ret < 0) { - fprintf(stderr, "Error writing the content file '%s' in fprintf(). %s.\n", path, strerror(errno)); + fprintf(stderr, "Error writing the content file '%s' in fprintf(). %s.\n", tmp, strerror(errno)); exit(EXIT_FAILURE); } @@ -501,7 +508,7 @@ void state_write(struct snapraid_state* state) ret = fprintf(f, "%s %u\n", tag, block->parity_pos); } if (ret < 0) { - fprintf(stderr, "Error writing the content file '%s' in fprintf(). %s.\n", path, strerror(errno)); + fprintf(stderr, "Error writing the content file '%s' in fprintf(). %s.\n", tmp, strerror(errno)); exit(EXIT_FAILURE); } @@ -516,27 +523,46 @@ void state_write(struct snapraid_state* state) /* than even in a system crash event we have one valid copy of the file. */ if (fflush(f) != 0) { - fprintf(stderr, "Error writing the content file '%s', in fflush(). %s.\n", path, strerror(errno)); + fprintf(stderr, "Error writing the content file '%s', in fflush(). %s.\n", tmp, strerror(errno)); exit(EXIT_FAILURE); } #if HAVE_FSYNC if (fsync(fileno(f)) != 0) { - fprintf(stderr, "Error writing the content file '%s' in fsync(). %s.\n", path, strerror(errno)); + fprintf(stderr, "Error writing the content file '%s' in fsync(). %s.\n", tmp, strerror(errno)); exit(EXIT_FAILURE); } #endif if (fclose(f) != 0) { - fprintf(stderr, "Error writing the content file '%s' in close(). %s.\n", path, strerror(errno)); + fprintf(stderr, "Error writing the content file '%s' in close(). %s.\n", tmp, strerror(errno)); exit(EXIT_FAILURE); } - if (rename(path, state->content) != 0) { - fprintf(stderr, "Error renaming the content file '%s' to '%s' in rename(). %s.\n", path, state->content, strerror(errno)); + if (rename(tmp, path) != 0) { + fprintf(stderr, "Error renaming the content file '%s' to '%s' in rename(). %s.\n", tmp, path, strerror(errno)); exit(EXIT_FAILURE); } + if (out_count_file) + *out_count_file = count_file; + if (out_count_block) + *out_count_block = count_block; +} + +void state_write(struct snapraid_state* state) +{ + unsigned count_file; + unsigned count_block; + tommy_node* node; + + node = tommy_list_head(&state->contentlist); + while (node) { + struct snapraid_content* content = node->data; + state_write_one(state, content->content, &count_file, &count_block); + node = node->next; + } + if (state->verbose) { printf("\tfile %u\n", count_file); printf("\tblock %u\n", count_block); diff --git a/state.h b/state.h index 5c78f7ce..0837bde1 100644 --- a/state.h +++ b/state.h @@ -37,11 +37,11 @@ struct snapraid_state { int expect_recoverable; /**< Expect presence of recoverable error in checking. */ int need_write; /**< If the state is changed. */ uint32_t block_size; /**< Block size in bytes. */ - char content[PATH_MAX]; /**< Path of the content file. */ char parity[PATH_MAX]; /**< Path of the parity file. */ char qarity[PATH_MAX]; /**< Path of the qarity file. */ unsigned level; /**< Number of parity levels. 1 for RAID5, 2 for RAID6. */ unsigned hash; /**< Hash kind used. */ + tommy_list contentlist; /**< List of content files. */ tommy_array diskarr; /**< Disk array. */ tommy_list excludelist; /**< List of exclusion. */ }; diff --git a/test-raid6.conf b/test-raid6.conf index fe9aced6..982b7221 100644 --- a/test-raid6.conf +++ b/test-raid6.conf @@ -2,6 +2,7 @@ block_size 1 parity test/parity q-parity test/q-parity content test/content +content test/q-content disk d1 test/disk1/ disk d2 test/disk2/ disk d3 test/disk3/