diff --git a/.version b/.version index f2f3fcc..48cf2f2 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -11.3 \ No newline at end of file +11.5 \ No newline at end of file diff --git a/HISTORY b/HISTORY index ad7411f..65a6d9c 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,20 @@ SnapRAID HISTORY ================ +11.5 2020/05 +============ + * Removed the default -march=native to allow to deploy in any machine. + * Fixed typos [Andrea Gelmini] + +11.4 2020/05 +============ + * Fix build errors due new gcc 10 default for -fno-common. + * In fixing, if a parity is filtered out, don't attempt to recover its size, + and proceed without it if missing. + * Avoid unnecessary parity read when fixing the parity itself. + This improves the 'fix' speed when a parity file is completely missing. + * Removed a build warning about major/minor defined now in sys/sysmacros.h. + 11.3 2018/11 ============ * Fixed handing of Linux devices that have multiple slaves. This affects @@ -139,7 +153,7 @@ SnapRAID HISTORY A workaround was to just run 'sync' one time with the -N, --force-nocopy option to disable the copy detection. * Restored the -O2 optimization option for Windows binaries, as -Og has - a too big performance penality. + a too big performance penalty. 9.2 2016/01 =========== @@ -412,7 +426,7 @@ SnapRAID HISTORY and Opteron. * Faster RAID5 and RAID6 implementation for ARM 64 bit CPUs. * If a silent error is found during a "sync" command, directly marks - the block as bad like in "scrub", without stopping the the "sync" + the block as bad like in "scrub", without stopping the "sync" process. * Sort files by inode when listing the directory. This improves the scanning performance. diff --git a/Makefile.am b/Makefile.am index 4c0c167..447d96b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -83,6 +83,7 @@ noinst_HEADERS = \ cmdline/murmur3test.c \ cmdline/spooky2.c \ cmdline/spooky2test.c \ + cmdline/metro.c \ cmdline/fnmatch.h \ cmdline/import.h \ cmdline/search.h \ @@ -158,7 +159,7 @@ maintainer-clean-local: CHECKFLAGS_COMMON = --test-skip-device --test-skip-self --test-force-progress --no-warnings --test-parity-limit=3333333 # --test-force-order-alpha -# Ensures to process files always in the same order despites +# Ensures to process files always in the same order despite # the inode, physical location, and dir order assigned by the OS. CHECKFLAGS_ALPHA = $(CHECKFLAGS_COMMON) --test-force-order-alpha @@ -499,7 +500,7 @@ endif $(FAILENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-run "rm bench/disk1/RUN-RM" --test-expect-failure sync echo RUN > bench/disk1/RUN-CHMOD if HAVE_POSIX -# Doesn't run this test as root because the root user overrride permissions +# Doesn't run this test as root because the root user override permissions if [[ $$EUID -ne 0 ]]; then \ $(FAILENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-run "chmod a-r bench/disk1/RUN-CHMOD" --test-expect-failure sync; \ fi diff --git a/Makefile.in b/Makefile.in index 73f8ac5..9524fd5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -429,6 +429,7 @@ noinst_HEADERS = \ cmdline/murmur3test.c \ cmdline/spooky2.c \ cmdline/spooky2test.c \ + cmdline/metro.c \ cmdline/fnmatch.h \ cmdline/import.h \ cmdline/search.h \ @@ -487,7 +488,7 @@ man_MANS = snapraid.1 CHECKFLAGS_COMMON = --test-skip-device --test-skip-self --test-force-progress --no-warnings --test-parity-limit=3333333 # --test-force-order-alpha -# Ensures to process files always in the same order despites +# Ensures to process files always in the same order despite # the inode, physical location, and dir order assigned by the OS. CHECKFLAGS_ALPHA = $(CHECKFLAGS_COMMON) --test-force-order-alpha @@ -1409,7 +1410,7 @@ check-local: @HAVE_THREAD_CHECKER_FALSE@ echo RUN > bench/disk1/RUN-RM @HAVE_THREAD_CHECKER_FALSE@ $(FAILENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-run "rm bench/disk1/RUN-RM" --test-expect-failure sync @HAVE_THREAD_CHECKER_FALSE@ echo RUN > bench/disk1/RUN-CHMOD -# Doesn't run this test as root because the root user overrride permissions +# Doesn't run this test as root because the root user override permissions @HAVE_POSIX_TRUE@@HAVE_THREAD_CHECKER_FALSE@ if [[ $$EUID -ne 0 ]]; then \ @HAVE_POSIX_TRUE@@HAVE_THREAD_CHECKER_FALSE@ $(FAILENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-run "chmod a-r bench/disk1/RUN-CHMOD" --test-expect-failure sync; \ @HAVE_POSIX_TRUE@@HAVE_THREAD_CHECKER_FALSE@ fi diff --git a/README b/README index 52a90b7..9033002 100644 --- a/README +++ b/README @@ -11,6 +11,8 @@ have a lot of big files that rarely change. Beside the ability to recover from disk failures, the other features of SnapRAID are: +* You can use disk already filled with files, without the need to + reformat them. You will access them like now. * All your data is hashed to ensure data integrity and to avoid silent corruption. * If the failed disks are too many to allow a recovery, @@ -18,12 +20,11 @@ features of SnapRAID are: All the data in the other disks is safe. * If you accidentally delete some files in a disk, you can recover them. -* You can start with already filled disks. * The disks can have different sizes. * You can add disks at any time. * It doesn't lock-in your data. You can stop using SnapRAID at any time without the need to reformat or move data. -* To access a file, a single disk needs to spin, saving power and +* To access a file, only a single disk needs to spin, saving power and producing less noise. The official site of SnapRAID is: diff --git a/TODO b/TODO index f02c44c..329b417 100644 --- a/TODO +++ b/TODO @@ -25,8 +25,8 @@ with a mono thread implementation with 100.0000 files. * Support more parity levels It can be done with a generic computation function, using intrinsic for SSSE3 and AVX instructions. -It would be intersting to compare performance with the hand-written -assembler functions. Eventially we can convert them to use intrinsic also. +It would be interesting to compare performance with the hand-written +assembler functions. Eventually we can convert them to use intrinsic also. https://sourceforge.net/p/snapraid/discussion/1677233/thread/9dbd7581/ * Extend haspdeep to support the SnapRAID hash : @@ -151,7 +151,7 @@ See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/cdea773f/ * Allocate parity minimizing concurrent use of it Each parity allocation should check for a parity range with less utilization by other disks. -We need to take care do disable this meachnism when the parity space +We need to take care do disable this mechanism when the parity space is near to fillup the parity partition. See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/1797bf7d/ + This increase the possibility of recovering with multiple failures with not @@ -182,7 +182,7 @@ allowing the user to choose where to put it. - It won't work with disks of different size. Suppose to have all disks of size N, with only one of size M>N. To fully use the M space, you can allocate a full N parity in such disk, -but the remaning space will also need additional parity in the other disks, +but the remaining space will also need additional parity in the other disks, in fact requiring a total of M parity for the array. In the end, we cannot avoid that the first biggest disk added is fully dedicated to parity, even if it means to leave some space unused. @@ -199,7 +199,7 @@ But it should be only few bits for each file. So, it should be manageable. A lot of discussions about this feature :) https://sourceforge.net/p/snapraid/discussion/1677233/thread/b2cd9385/ - The only benefit is to distribute better the data. This could help the recovery process, -in case of multiple failures. But no real usability or funtionality benefit in the normal +in case of multiple failures. But no real usability or functionality benefit in the normal case. * https://sourceforge.net/p/snapraid/discussion/1677233/thread/2cb97e8a/ @@ -229,7 +229,7 @@ are automatically deleted. * Checks if splitting hash/parity computation in 4K pages can improve speed in sync. That should increase cache locality, -because we read the data two times for hash and and parity, +because we read the data two times for hash and parity, and if we manage to keep it in the cache, we should save time. - We now hash first the faster disks, and this could reduce performance as we'll have to wait for all disks. diff --git a/acinclude.m4 b/acinclude.m4 index 1b92cc9..96e9c5f 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1,7 +1,7 @@ dnl @synopsis AC_CHECK_CC_OPT(flag, ifyes, ifno) dnl -dnl Shows a message as like "checking wether gcc accepts flag ... no" -dnl and executess ifyes or ifno. +dnl Shows a message as like "checking whether gcc accepts flag ... no" +dnl and executes ifyes or ifno. AC_DEFUN([AC_CHECK_CC_OPT], [ diff --git a/cmdline/check.c b/cmdline/check.c index 72012df..b3d2048 100644 --- a/cmdline/check.c +++ b/cmdline/check.c @@ -574,7 +574,7 @@ static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsign } else { log_tag("recover_unsync:%u:%u: Skipped for%s%s\n", pos, n, !something_to_recover ? " nothing to recover" : "", - !something_unsynced ? " nothing unsynched" : "" + !something_unsynced ? " nothing unsynced" : "" ); } @@ -1441,7 +1441,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna char path[PATH_MAX]; struct stat st; struct snapraid_file* file; - int unsuccesful = 0; + int unsuccessful = 0; file = node->data; node = node->next; /* next node */ @@ -1460,24 +1460,24 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub); ret = stat(path, &st); if (ret == -1) { - unsuccesful = 1; + unsuccessful = 1; log_error("Error stating empty file '%s'. %s.\n", path, strerror(errno)); log_tag("error:%s:%s: Empty file stat error\n", disk->name, esc_tag(file->sub, esc_buffer)); ++error; } else if (!S_ISREG(st.st_mode)) { - unsuccesful = 1; + unsuccessful = 1; log_tag("error:%s:%s: Empty file error for not regular file\n", disk->name, esc_tag(file->sub, esc_buffer)); ++error; } else if (st.st_size != 0) { - unsuccesful = 1; + unsuccessful = 1; log_tag("error:%s:%s: Empty file error for size '%" PRIu64 "'\n", disk->name, esc_tag(file->sub, esc_buffer), (uint64_t)st.st_size); ++error; } - if (fix && unsuccesful) { + if (fix && unsuccessful) { int f; /* create the ancestor directories */ @@ -1552,7 +1552,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna struct stat st; struct stat stto; struct snapraid_link* slink; - int unsuccesful = 0; + int unsuccessful = 0; int unrecoverable = 0; slink = node->data; @@ -1568,13 +1568,13 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna pathprint(path, sizeof(path), "%s%s", disk->dir, slink->sub); ret = stat(path, &st); if (ret == -1) { - unsuccesful = 1; + unsuccessful = 1; log_error("Error stating hardlink '%s'. %s.\n", path, strerror(errno)); log_tag("hardlink_error:%s:%s:%s: Hardlink stat error\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt)); ++error; } else if (!S_ISREG(st.st_mode)) { - unsuccesful = 1; + unsuccessful = 1; log_tag("hardlink_error:%s:%s:%s: Hardlink error for not regular file\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt)); ++error; @@ -1584,7 +1584,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna pathprint(pathto, sizeof(pathto), "%s%s", disk->dir, slink->linkto); ret = stat(pathto, &stto); if (ret == -1) { - unsuccesful = 1; + unsuccessful = 1; if (errno == ENOENT) { unrecoverable = 1; @@ -1604,12 +1604,12 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna log_tag("hardlink_error:%s:%s:%s: Hardlink to stat error\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt)); ++error; } else if (!S_ISREG(stto.st_mode)) { - unsuccesful = 1; + unsuccessful = 1; log_tag("hardlink_error:%s:%s:%s: Hardlink-to error for not regular file\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt)); ++error; - } else if (!unsuccesful && st.st_ino != stto.st_ino) { - unsuccesful = 1; + } else if (!unsuccessful && st.st_ino != stto.st_ino) { + unsuccessful = 1; log_error("Mismatch hardlink '%s' and '%s'. Different inode.\n", path, pathto); log_tag("hardlink_error:%s:%s:%s: Hardlink mismatch for different inode\n", disk->name, esc_tag(slink->sub, esc_buffer), esc_tag(slink->linkto, esc_buffer_alt)); @@ -1620,13 +1620,13 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna pathprint(path, sizeof(path), "%s%s", disk->dir, slink->sub); ret = readlink(path, linkto, sizeof(linkto)); if (ret < 0) { - unsuccesful = 1; + unsuccessful = 1; log_error("Error reading symlink '%s'. %s.\n", path, strerror(errno)); log_tag("symlink_error:%s:%s: Symlink read error\n", disk->name, esc_tag(slink->sub, esc_buffer)); ++error; } else if (ret >= PATH_MAX) { - unsuccesful = 1; + unsuccessful = 1; log_error("Error reading symlink '%s'. Symlink too long.\n", path); log_tag("symlink_error:%s:%s: Symlink read error\n", disk->name, esc_tag(slink->sub, esc_buffer)); @@ -1635,7 +1635,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna linkto[ret] = 0; if (strcmp(linkto, slink->linkto) != 0) { - unsuccesful = 1; + unsuccessful = 1; log_tag("symlink_error:%s:%s: Symlink data error '%s' instead of '%s'\n", disk->name, esc_tag(slink->sub, esc_buffer), linkto, slink->linkto); ++error; @@ -1643,7 +1643,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna } } - if (fix && unsuccesful && !unrecoverable) { + if (fix && unsuccessful && !unrecoverable) { /* create the ancestor directories */ ret = mkancestor(path); if (ret != 0) { @@ -1720,7 +1720,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna char path[PATH_MAX]; struct stat st; struct snapraid_dir* dir; - int unsuccesful = 0; + int unsuccessful = 0; dir = node->data; node = node->next; /* next node */ @@ -1734,19 +1734,19 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna pathprint(path, sizeof(path), "%s%s", disk->dir, dir->sub); ret = stat(path, &st); if (ret == -1) { - unsuccesful = 1; + unsuccessful = 1; log_error("Error stating dir '%s'. %s.\n", path, strerror(errno)); log_tag("dir_error:%s:%s: Dir stat error\n", disk->name, esc_tag(dir->sub, esc_buffer)); ++error; } else if (!S_ISDIR(st.st_mode)) { - unsuccesful = 1; + unsuccessful = 1; log_tag("dir_error:%s:%s: Dir error for not directory\n", disk->name, esc_tag(dir->sub, esc_buffer)); ++error; } - if (fix && unsuccesful) { + if (fix && unsuccessful) { /* create the ancestor directories */ ret = mkancestor(path); if (ret != 0) { @@ -1973,20 +1973,32 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b } parity_ptr[l] = &parity[l]; - ret = parity_create(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size); - if (ret == -1) { - /* LCOV_EXCL_START */ - log_fatal("WARNING! Without an accessible %s file, it isn't possible to fix any error.\n", lev_name(l)); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ - } - ret = parity_chsize(parity_ptr[l], &state->parity[l], 0, size, state->block_size, state->opt.skip_fallocate, state->opt.skip_space_holder); - if (ret == -1) { - /* LCOV_EXCL_START */ - log_fatal("WARNING! Without an accessible %s file, it isn't possible to sync.\n", lev_name(l)); - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ + /* if the parity is excluded */ + if (state->parity[l].is_excluded_by_filter) { + /* open for reading, and ignore error */ + ret = parity_open(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size); + if (ret == -1) { + /* continue anyway */ + parity_ptr[l] = 0; + } + } else { + /* open for writing */ + ret = parity_create(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size); + if (ret == -1) { + /* LCOV_EXCL_START */ + log_fatal("WARNING! Without an accessible %s file, it isn't possible to fix any error.\n", lev_name(l)); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } + + ret = parity_chsize(parity_ptr[l], &state->parity[l], 0, size, state->block_size, state->opt.skip_fallocate, state->opt.skip_space_holder); + if (ret == -1) { + /* LCOV_EXCL_START */ + log_fatal("WARNING! Without an accessible %s file, it isn't possible to sync.\n", lev_name(l)); + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } } } } else if (!state->opt.auditonly) { @@ -2030,14 +2042,26 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b /* try to close only if opened */ for (l = 0; l < state->level; ++l) { if (parity_ptr[l]) { + /* if fixing and not excluded, truncate parity not valid */ + if (fix && !state->parity[l].is_excluded_by_filter) { + ret = parity_truncate(parity_ptr[l]); + if (ret == -1) { + /* LCOV_EXCL_START */ + log_fatal("DANGER! Unexpected truncate error in %s disk.\n", lev_name(l)); + ++error; + /* continue, as we are already exiting */ + /* LCOV_EXCL_STOP */ + } + } + ret = parity_close(parity_ptr[l]); - /* LCOV_EXCL_START */ if (ret == -1) { + /* LCOV_EXCL_START */ log_fatal("DANGER! Unexpected close error in %s disk.\n", lev_name(l)); ++error; /* continue, as we are already exiting */ + /* LCOV_EXCL_STOP */ } - /* LCOV_EXCL_STOP */ } } diff --git a/cmdline/device.c b/cmdline/device.c index f170ad6..605fdc3 100644 --- a/cmdline/device.c +++ b/cmdline/device.c @@ -818,7 +818,7 @@ static void state_smart(unsigned n, tommy_list* low) /* |<##################################################################72>|####80>| */ printf("These values are the probabilities that in the next year you'll have a\n"); - printf("sequence of failures that the parity WONT be able to recover, assuming\n"); + printf("sequence of failures that the parity WON'T be able to recover, assuming\n"); printf("that you regularly scrub, and in case repair, the array in the specified\n"); printf("time.\n"); diff --git a/cmdline/elem.h b/cmdline/elem.h index e821e41..0c4a555 100644 --- a/cmdline/elem.h +++ b/cmdline/elem.h @@ -349,7 +349,7 @@ struct snapraid_disk { block_off_t first_free_block; int has_volatile_inodes; /**< If the underline file-system has not persistent inodes. */ - int has_volatile_hardlinks; /**< If the underline file-system has not syncronized metadata for hardlink (NTFS). */ + int has_volatile_hardlinks; /**< If the underline file-system has not synchronized metadata for hardlink (NTFS). */ int has_unreliable_physical; /**< If the physical offset of files has duplicates. */ int has_different_uuid; /**< If the disk has a different UUID, meaning that it is not the same file-system. */ int has_unsupported_uuid; /**< If the disk doesn't report UUID, meaning it's not supported. */ @@ -1000,7 +1000,7 @@ int fs_check(struct snapraid_disk* disk); * After this call you can use the par2file/par2block operations * to query the relation. * - * \note This function is NOT thread-safe as it uses the the disk cache. + + * \note This function is NOT thread-safe as it uses the disk cache. + */ void fs_allocate(struct snapraid_disk* disk, block_off_t parity_pos, struct snapraid_file* file, block_off_t file_pos); @@ -1010,7 +1010,7 @@ void fs_allocate(struct snapraid_disk* disk, block_off_t parity_pos, struct snap * After this call the par2file/par2block operations * won't find anymore the parity association. * - * \note This function is NOT thread-safe as it uses the the disk cache. + * \note This function is NOT thread-safe as it uses the disk cache. */ void fs_deallocate(struct snapraid_disk* disk, block_off_t pos); @@ -1129,7 +1129,7 @@ static inline snapraid_info info_make(time_t last_access, int error, int rehash, /** * Extract the time information. * This is the last time when the block was know to be correct. - * The "scrubbed" info tells if the time is referreing at the latest sync or scrub. + * The "scrubbed" info tells if the time is referring at the latest sync or scrub. */ static inline time_t info_get_time(snapraid_info info) { diff --git a/cmdline/io.c b/cmdline/io.c index c71ba41..156d512 100644 --- a/cmdline/io.c +++ b/cmdline/io.c @@ -19,6 +19,19 @@ #include "io.h" +void (*io_start)(struct snapraid_io* io, + block_off_t blockstart, block_off_t blockmax, + int (*block_is_enabled)(void* arg, block_off_t), void* blockarg) = 0; +void (*io_stop)(struct snapraid_io* io) = 0; +block_off_t (*io_read_next)(struct snapraid_io* io, void*** buffer) = 0; +struct snapraid_task* (*io_data_read)(struct snapraid_io* io, unsigned* diskcur, unsigned* waiting_map, unsigned* waiting_mac) = 0; +struct snapraid_task* (*io_parity_read)(struct snapraid_io* io, unsigned* levcur, unsigned* waiting_map, unsigned* waiting_mac) = 0; +void (*io_parity_write)(struct snapraid_io* io, unsigned* levcur, unsigned* waiting_map, unsigned* waiting_mac) = 0; +void (*io_write_preset)(struct snapraid_io* io, block_off_t blockcur, int skip) = 0; +void (*io_write_next)(struct snapraid_io* io, block_off_t blockcur, int skip, int* writer_error) = 0; +void (*io_refresh)(struct snapraid_io* io) = 0; + + /** * Get the next block position to process. */ diff --git a/cmdline/io.h b/cmdline/io.h index 82ec744..a0cfb63 100644 --- a/cmdline/io.h +++ b/cmdline/io.h @@ -306,21 +306,21 @@ void io_init(struct snapraid_io* io, struct snapraid_state* state, struct snapraid_parity_handle* parity_handle_map, unsigned parity_handle_max); /** - * Deinitialize te InputOutput workers. + * Deinitialize the InputOutput workers. */ void io_done(struct snapraid_io* io); /** * Start all the worker threads. */ -void (*io_start)(struct snapraid_io* io, +extern void (*io_start)(struct snapraid_io* io, block_off_t blockstart, block_off_t blockmax, int (*block_is_enabled)(void* arg, block_off_t), void* blockarg); /** * Stop all the worker threads. */ -void (*io_stop)(struct snapraid_io* io); +extern void (*io_stop)(struct snapraid_io* io); /** * Next read position. @@ -332,7 +332,7 @@ void (*io_stop)(struct snapraid_io* io); * \param buffer The data buffers to use for this position. * \return The parity position. */ -block_off_t (*io_read_next)(struct snapraid_io* io, void*** buffer); +extern block_off_t (*io_read_next)(struct snapraid_io* io, void*** buffer); /** * Read a data block. @@ -343,7 +343,7 @@ block_off_t (*io_read_next)(struct snapraid_io* io, void*** buffer); * \param diskcur The position of the data block in the ::handle_map vector. * \return The completed task. */ -struct snapraid_task* (*io_data_read)(struct snapraid_io* io, unsigned* diskcur, unsigned* waiting_map, unsigned* waiting_mac); +extern struct snapraid_task* (*io_data_read)(struct snapraid_io* io, unsigned* diskcur, unsigned* waiting_map, unsigned* waiting_mac); /** * Read a parity block. @@ -354,7 +354,7 @@ struct snapraid_task* (*io_data_read)(struct snapraid_io* io, unsigned* diskcur, * \param levcur The position of the parity block in the ::parity_handle_map vector. * \return The completed task. */ -struct snapraid_task* (*io_parity_read)(struct snapraid_io* io, unsigned* levcur, unsigned* waiting_map, unsigned* waiting_mac); +extern struct snapraid_task* (*io_parity_read)(struct snapraid_io* io, unsigned* levcur, unsigned* waiting_map, unsigned* waiting_mac); /** * Write of a parity block. @@ -364,7 +364,7 @@ struct snapraid_task* (*io_parity_read)(struct snapraid_io* io, unsigned* levcur * \param io InputOutput context. * \param levcur The position of the parity block in the ::parity_handle_map vector. */ -void (*io_parity_write)(struct snapraid_io* io, unsigned* levcur, unsigned* waiting_map, unsigned* waiting_mac); +extern void (*io_parity_write)(struct snapraid_io* io, unsigned* levcur, unsigned* waiting_map, unsigned* waiting_mac); /** * Preset the write position. @@ -376,7 +376,7 @@ void (*io_parity_write)(struct snapraid_io* io, unsigned* levcur, unsigned* wait * \param blockcur The parity position to write. * \param skip Skip the writes, in case parity doesn't need to be updated. */ -void (*io_write_preset)(struct snapraid_io* io, block_off_t blockcur, int skip); +extern void (*io_write_preset)(struct snapraid_io* io, block_off_t blockcur, int skip); /** * Next write position. @@ -389,12 +389,12 @@ void (*io_write_preset)(struct snapraid_io* io, block_off_t blockcur, int skip); * \param skip Skip the writes, in case parity doesn't need to be updated. * \param writer_error Return the number of errors. Vector of IO_WRITER_ERROR_MAX elements. */ -void (*io_write_next)(struct snapraid_io* io, block_off_t blockcur, int skip, int* writer_error); +extern void (*io_write_next)(struct snapraid_io* io, block_off_t blockcur, int skip, int* writer_error); /** * Refresh the number of cached blocks for all data and parity disks. */ -void (*io_refresh)(struct snapraid_io* io); +extern void (*io_refresh)(struct snapraid_io* io); #endif diff --git a/cmdline/metro.c b/cmdline/metro.c new file mode 100644 index 0000000..18f4027 --- /dev/null +++ b/cmdline/metro.c @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2019 Andrea Mazzoleni + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * Derivative work from metrohash128.cpp + * + * metrohash128.cpp + * + * Copyright 2015-2018 J. Andrew Rogers + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +static const uint64_t k0 = 0xC83A91E1; +static const uint64_t k1 = 0x8648DBDB; +static const uint64_t k2 = 0x7BDEC03B; +static const uint64_t k3 = 0x2F5870A5; + +void MetroHash128(const void* data, size_t size, const uint8_t* seed, uint8_t* digest) +{ + const uint8_t* ptr = data; + uint64_t v[4]; + + v[0] = (util_read64(seed) - k0) * k3; + v[1] = (util_read64(seed + 8) + k1) * k2; + + if (size >= 32) { + v[2] = (util_read64(seed) + k0) * k2; + v[3] = (util_read64(seed + 8) - k1) * k3; + + do { + v[0] += util_read64(ptr) * k0; ptr += 8; v[0] = util_rotr64(v[0], 29) + v[2]; + v[1] += util_read64(ptr) * k1; ptr += 8; v[1] = util_rotr64(v[1], 29) + v[3]; + v[2] += util_read64(ptr) * k2; ptr += 8; v[2] = util_rotr64(v[2], 29) + v[0]; + v[3] += util_read64(ptr) * k3; ptr += 8; v[3] = util_rotr64(v[3], 29) + v[1]; + size -= 32; + } while (size >= 32); + + v[2] ^= util_rotr64(((v[0] + v[3]) * k0) + v[1], 21) * k1; + v[3] ^= util_rotr64(((v[1] + v[2]) * k1) + v[0], 21) * k0; + v[0] ^= util_rotr64(((v[0] + v[2]) * k0) + v[3], 21) * k1; + v[1] ^= util_rotr64(((v[1] + v[3]) * k1) + v[2], 21) * k0; + } + + if (size >= 16) { + v[0] += util_read64(ptr) * k2; ptr += 8; v[0] = util_rotr64(v[0], 33) * k3; + v[1] += util_read64(ptr) * k2; ptr += 8; v[1] = util_rotr64(v[1], 33) * k3; + v[0] ^= util_rotr64((v[0] * k2) + v[1], 45) * k1; + v[1] ^= util_rotr64((v[1] * k3) + v[0], 45) * k0; + size -= 16; + } + + if (size >= 8) { + v[0] += util_read64(ptr) * k2; ptr += 8; v[0] = util_rotr64(v[0], 33) * k3; + v[0] ^= util_rotr64((v[0] * k2) + v[1], 27) * k1; + size -= 8; + } + + if (size >= 4) { + v[1] += util_read32(ptr) * k2; ptr += 4; v[1] = util_rotr64(v[1], 33) * k3; + v[1] ^= util_rotr64((v[1] * k3) + v[0], 46) * k0; + size -= 4; + } + + if (size >= 2) { + v[0] += util_read16(ptr) * k2; ptr += 2; v[0] = util_rotr64(v[0], 33) * k3; + v[0] ^= util_rotr64((v[0] * k2) + v[1], 22) * k1; + size -= 2; + } + + if (size >= 1) { + v[1] += util_read8(ptr) * k2; v[1] = util_rotr64(v[1], 33) * k3; + v[1] ^= util_rotr64((v[1] * k3) + v[0], 58) * k0; + } + + v[0] += util_rotr64((v[0] * k0) + v[1], 13); + v[1] += util_rotr64((v[1] * k1) + v[0], 37); + v[0] += util_rotr64((v[0] * k2) + v[1], 13); + v[1] += util_rotr64((v[1] * k3) + v[0], 37); + + util_write64(digest, v[0]); + util_write64(digest + 8, v[0]); +} + diff --git a/cmdline/mingw.c b/cmdline/mingw.c index ef10ee8..5b8c9d4 100644 --- a/cmdline/mingw.c +++ b/cmdline/mingw.c @@ -1556,7 +1556,7 @@ int windows_link(const char* existing, const char* file) } /** - * In Windows 10 allow creationg of symblink by not priviliged user. + * In Windows 10 allow creation of symblink by not privileged user. * * See: Symlinks in Windows 10! * https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/#cQG7cx48oGH86lkI.97 @@ -1724,7 +1724,7 @@ int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_har if (has_persistent_inode) *has_persistent_inode = 1; - /* NTFS doesn't syncronize hardlinks metadata */ + /* NTFS doesn't synchronize hardlinks metadata */ if (has_syncronized_hardlinks) *has_syncronized_hardlinks = 0; diff --git a/cmdline/parity.c b/cmdline/parity.c index 6bfdbcd..e4569fe 100644 --- a/cmdline/parity.c +++ b/cmdline/parity.c @@ -217,6 +217,9 @@ int parity_create(struct snapraid_parity_handle* handle, const struct snapraid_p /* LCOV_EXCL_STOP */ } + /* the initial valid size is the size on disk */ + split->valid_size = split->st.st_size; + /** * If the parity size is not yet set, set it now. * This happens when expanding the number of parities, @@ -528,6 +531,10 @@ static int parity_handle_chsize(struct snapraid_split_handle* split, data_off_t /* LCOV_EXCL_STOP */ } + /* if we shrink, update the valid size, but don't update when growing */ + if (split->valid_size > split->st.st_size) + split->valid_size = split->st.st_size; + return 0; } @@ -697,6 +704,9 @@ int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_par /* LCOV_EXCL_STOP */ } + /* the initial valid size is the size on disk */ + split->valid_size = split->st.st_size; + /** * If the parity size is not yet set, set it now. * This happens when expanding the number of parities, @@ -751,7 +761,7 @@ int parity_sync(struct snapraid_parity_handle* handle) ret = fsync(split->f); if (ret != 0) { /* LCOV_EXCL_START */ - log_fatal("Error synching parity file '%s'. %s.\n", split->path, strerror(errno)); + log_fatal("Error syncing parity file '%s'. %s.\n", split->path, strerror(errno)); return -1; /* LCOV_EXCL_STOP */ } @@ -761,6 +771,30 @@ int parity_sync(struct snapraid_parity_handle* handle) return 0; } +int parity_truncate(struct snapraid_parity_handle* handle) +{ + unsigned s; + int f_ret = 0; + + for (s = 0; s < handle->split_mac; ++s) { + struct snapraid_split_handle* split = &handle->split_map[s]; + int ret; + + /* truncate any data that we know it's not valid */ + ret = ftruncate(split->f, split->valid_size); + if (ret != 0) { + /* LCOV_EXCL_START */ + log_fatal("Error truncating the parity file '%s' to size %" PRIu64 ". %s.\n", split->path, split->valid_size, strerror(errno)); + f_ret = -1; + /* LCOV_EXCL_STOP */ + + /* continue to truncate the others */ + } + } + + return f_ret; +} + int parity_close(struct snapraid_parity_handle* handle) { unsigned s; @@ -826,6 +860,10 @@ int parity_write(struct snapraid_parity_handle* handle, block_off_t pos, unsigne /* LCOV_EXCL_STOP */ } + /* update the valid range */ + if (split->valid_size < offset + block_size) + split->valid_size = offset + block_size; + write_ret = pwrite(split->f, block_buffer, block_size, offset); if (write_ret != (ssize_t)block_size) { /* conversion is safe because block_size is always small */ /* LCOV_EXCL_START */ @@ -867,6 +905,14 @@ int parity_read(struct snapraid_parity_handle* handle, block_off_t pos, unsigned /* LCOV_EXCL_STOP */ } + /* if read is completely out of the valid range */ + if (offset >= split->valid_size) { + /* LCOV_EXCL_START */ + out("Missing data reading file '%s' at offset %" PRIu64 " for size %u.\n", split->path, offset, block_size); + return -1; + /* LCOV_EXCL_STOP */ + } + count = 0; do { read_ret = pread(split->f, block_buffer + count, block_size - count, offset + count); diff --git a/cmdline/parity.h b/cmdline/parity.h index 056362e..3380eb7 100644 --- a/cmdline/parity.h +++ b/cmdline/parity.h @@ -36,6 +36,16 @@ struct snapraid_split_handle { */ data_off_t size; + /** + * Valid size of the parity split. + * This is the size effectively written, and not the result of a chsize operation. + * It's used to make read operations failing if read over that size. + * + * Parity is also truncated to that size when fixing it, in case of a Break (Ctrl+C) + * of the program. + */ + data_off_t valid_size; + /** * Artificial size limit for testing. * 0 means unlimited. @@ -113,6 +123,11 @@ int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_par */ int parity_sync(struct snapraid_parity_handle* handle); +/** + * Truncate the parity file to the valid size. + */ +int parity_truncate(struct snapraid_parity_handle* handle); + /** * Close the parity file. */ diff --git a/cmdline/pool.c b/cmdline/pool.c index 44e3510..85cfc40 100644 --- a/cmdline/pool.c +++ b/cmdline/pool.c @@ -369,7 +369,7 @@ static void make_link(tommy_hashdyn* poolset, const char* pool_dir, const char* #ifdef _WIN32 } else if (errno == EPERM) { /* LCOV_EXCL_START */ - log_fatal("You must run as Adminstrator to be able to create symlinks.\n"); + log_fatal("You must run as Administrator to be able to create symlinks.\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ #endif diff --git a/cmdline/portable.h b/cmdline/portable.h index 053ad85..5c75428 100644 --- a/cmdline/portable.h +++ b/cmdline/portable.h @@ -35,7 +35,7 @@ #define __USE_MINGW_ANSI_STDIO 1 /** - * Define the MSVCRT version targetting Windows Vista. + * Define the MSVCRT version targeting Windows Vista. */ #define __MSVCRT_VERSION__ 0x0600 @@ -198,9 +198,11 @@ #include #endif -#if MAJOR_IN_MKDEV +#if HAVE_SYS_MKDEV #include -#elif MAJOR_IN_SYSMACROS +#endif + +#if HAVE_SYS_SYSMACROS_H #include #endif @@ -387,14 +389,14 @@ void os_clear(void); * * If no log file is selected, it's 0. */ -FILE* stdlog; +extern FILE* stdlog; /** * Exit codes for testing. */ -int exit_success; -int exit_failure; -int exit_sync_needed; +extern int exit_success; +extern int exit_failure; +extern int exit_sync_needed; #undef EXIT_SUCCESS #undef EXIT_FAILURE #define EXIT_SUCCESS exit_success diff --git a/cmdline/scan.c b/cmdline/scan.c index 8e70ff3..f879cd3 100644 --- a/cmdline/scan.c +++ b/cmdline/scan.c @@ -501,7 +501,7 @@ static void scan_file_refresh(struct snapraid_scan* scan, const char* sub, struc * because the metadata in the directory is updated only when the file * is closed. * - * The same happens for hardlinks that duplicate metatada. + * The same happens for hardlinks that duplicate metadata. * The link metadata is updated only when the link is opened. * This extends also to st_size and st_nlink. * diff --git a/cmdline/scrub.c b/cmdline/scrub.c index 20a7ead..d69f3f0 100644 --- a/cmdline/scrub.c +++ b/cmdline/scrub.c @@ -665,7 +665,8 @@ static int state_scrub_process(struct snapraid_state* state, struct snapraid_par log_fatal("DANGER! Unexpected data errors! The failing blocks are now marked as bad!\n"); if (io_error || silent_error) { log_fatal("Use 'snapraid status' to list the bad blocks.\n"); - log_fatal("Use 'snapraid -e fix' to recover.\n"); + log_fatal("Use 'snapraid -e fix' to recover them.\n"); + log_fatal("Use 'snapraid -p bad scrub' to recheck after fixing.\n"); } log_tag("summary:error_file:%u\n", error); diff --git a/cmdline/selftest.c b/cmdline/selftest.c index b1e355a..8f79e5c 100644 --- a/cmdline/selftest.c +++ b/cmdline/selftest.c @@ -632,7 +632,7 @@ void selftest(void) } if (raid_test_par(RAID_MODE_CAUCHY, 1, 256) != 0) { /* LCOV_EXCL_START */ - log_fatal("Failed GEN Cauchy test sigle data disk\n"); + log_fatal("Failed GEN Cauchy test single data disk\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } diff --git a/cmdline/snapraid.c b/cmdline/snapraid.c index 07103a6..ec4f839 100644 --- a/cmdline/snapraid.c +++ b/cmdline/snapraid.c @@ -1001,6 +1001,10 @@ int main(int argc, char* argv[]) switch (operation) { case OPERATION_FIX : case OPERATION_CHECK : + case OPERATION_SMART : + case OPERATION_DEVICES : + case OPERATION_SPINUP : + case OPERATION_SPINDOWN : break; default : if (opt.force_device) { diff --git a/cmdline/speed.c b/cmdline/speed.c index f3ecdf8..73d2722 100644 --- a/cmdline/speed.c +++ b/cmdline/speed.c @@ -216,6 +216,7 @@ void speed(int period) printf("%8s", "best"); printf("%8s", "murmur3"); printf("%8s", "spooky2"); + printf("%8s", "metro"); printf("\n"); printf("%8s", "hash"); @@ -245,6 +246,14 @@ void speed(int period) memhash(HASH_SPOOKY2, seed, digest, v[j], size); } SPEED_STOP + printf("%8" PRIu64, ds / dt); + fflush(stdout); + + SPEED_START { + for (j = 0; j < nd; ++j) + memhash(HASH_METRO, seed, digest, v[j], size); + } SPEED_STOP + printf("%8" PRIu64, ds / dt); printf("\n"); printf("\n"); diff --git a/cmdline/state.c b/cmdline/state.c index b09fba2..3b04e96 100644 --- a/cmdline/state.c +++ b/cmdline/state.c @@ -279,7 +279,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, t struct snapraid_disk* other = j->data; if (disk->device == other->device) { if (state->opt.force_device) { - /* note tha we just ignore the issue */ + /* note that we just ignore the issue */ /* and we DON'T mark the disk to be skipped */ /* because we want to use these disks */ if (!state->opt.no_warnings) @@ -310,15 +310,23 @@ static void state_config_check(struct snapraid_state* state, const char* path, t for (l = 0; l < state->level; ++l) { for (s = 0; s < state->parity[l].split_mac; ++s) { if (disk->device == state->parity[l].split_map[s].device) { - /* LCOV_EXCL_START */ - log_fatal("Disk '%s' and %s '%s' are on the same device.\n", disk->dir, lev_name(l), state->parity[l].split_map[s].path); + if (state->opt.force_device) { + /* note that we just ignore the issue */ + /* and we DON'T mark the disk to be skipped */ + /* because we want to use these disks */ + if (!state->opt.no_warnings) + log_fatal("DANGER! Ignoring that disks '%s' and %s '%s' are on the same device\n", disk->dir, lev_name(l), state->parity[l].split_map[s].path); + } else { + /* LCOV_EXCL_START */ + log_fatal("Disk '%s' and %s '%s' are on the same device.\n", disk->dir, lev_name(l), state->parity[l].split_map[s].path); #ifdef _WIN32 - log_fatal("Both have the serial number '%" PRIx64 "'.\n", disk->device); - log_fatal("Try using the 'VolumeID' tool by 'Mark Russinovich'\n"); - log_fatal("to change one of the disk serial.\n"); + log_fatal("Both have the serial number '%" PRIx64 "'.\n", disk->device); + log_fatal("Try using the 'VolumeID' tool by 'Mark Russinovich'\n"); + log_fatal("to change one of the disk serial.\n"); #endif - exit(EXIT_FAILURE); - /* LCOV_EXCL_STOP */ + exit(EXIT_FAILURE); + /* LCOV_EXCL_STOP */ + } } } } @@ -364,7 +372,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, t for (t = 0; t < state->parity[j].split_mac; ++t) { if (state->parity[l].split_map[s].device == state->parity[j].split_map[t].device) { if (state->opt.force_device) { - /* note tha we just ignore the issue */ + /* note that we just ignore the issue */ /* and we DON'T mark the disk to be skipped */ /* because we want to use these disks */ if (!state->opt.no_warnings) @@ -623,7 +631,7 @@ void state_config(struct snapraid_state* state, const char* path, const char* co } state->block_size *= KIBI; } else if (strcmp(tag, "hashsize") == 0 - || strcmp(tag, "hash_size") == 0 /* v11.0 used incorretly this one, kept now for backward compatibility */ + || strcmp(tag, "hash_size") == 0 /* v11.0 used incorrectly this one, kept now for backward compatibility */ ) { uint32_t hash_size; @@ -1618,7 +1626,7 @@ static void state_content_check(struct snapraid_state* state, const char* path) /** * Check if the position is REQUIRED, or we can completely clear it from the state. * - * Note that position with only DELETED blocks are discarged. + * Note that position with only DELETED blocks are discharged. */ static int fs_position_is_required(struct snapraid_state* state, block_off_t pos) { @@ -1844,7 +1852,7 @@ static void state_read_content(struct snapraid_state* state, const char* path, S if (state->block_size == 0) { /* LCOV_EXCL_START */ decoding_error(path, f); - log_fatal("Internal incosistency due zero blocksize!\n"); + log_fatal("Internal inconsistency due zero blocksize!\n"); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } @@ -2398,6 +2406,9 @@ static void state_read_content(struct snapraid_state* state, const char* path, S case 'k' : state->hash = HASH_SPOOKY2; break; + case 'm' : + state->hash = HASH_METRO; + break; default : /* LCOV_EXCL_START */ decoding_error(path, f); @@ -2425,6 +2436,9 @@ static void state_read_content(struct snapraid_state* state, const char* path, S case 'k' : state->prevhash = HASH_SPOOKY2; break; + case 'm' : + state->prevhash = HASH_METRO; + break; default : /* LCOV_EXCL_START */ decoding_error(path, f); @@ -2947,6 +2961,8 @@ static void* state_write_thread(void* arg) sputc('u', f); } else if (state->hash == HASH_SPOOKY2) { sputc('k', f); + } else if (state->hash == HASH_METRO) { + sputc('m', f); } else { /* LCOV_EXCL_START */ log_fatal("Unexpected hash when writing the content file '%s'.\n", serrorfile(f)); @@ -2970,6 +2986,8 @@ static void* state_write_thread(void* arg) sputc('u', f); } else if (state->prevhash == HASH_SPOOKY2) { sputc('k', f); + } else if (state->prevhash == HASH_METRO) { + sputc('m', f); } else { /* LCOV_EXCL_START */ log_fatal("Unexpected prevhash when writing the content file '%s'.\n", serrorfile(f)); @@ -3837,10 +3855,14 @@ struct state_verify_thread_context { static void* state_verify_thread(void* arg) { struct state_verify_thread_context* context = arg; + struct snapraid_content* content = context->content; STREAM* f = context->f; unsigned char buf[4]; uint32_t crc_stored; uint32_t crc_computed; + uint64_t start; + + start = tick_ms(); if (sdeplete(f, buf) != 0) { /* LCOV_EXCL_START */ @@ -3872,6 +3894,8 @@ static void* state_verify_thread(void* arg) /* LCOV_EXCL_STOP */ } + msg_progress("Verified %s in %" PRIu64 " seconds\n", content->content, (tick_ms() - start) / 1000); + return 0; } @@ -4155,7 +4179,7 @@ void state_filter(struct snapraid_state* state, tommy_list* filterlist_file, tom } } - /* if we are filtering by disk, exclude any parity not explicitely included */ + /* if we are filtering by disk, exclude any parity not explicitly included */ if (!tommy_list_empty(filterlist_disk)) { /* for each parity disk */ for (l = 0; l < state->level; ++l) { @@ -4463,7 +4487,8 @@ int state_progress(struct snapraid_state* state, struct snapraid_io* io, block_o ) { time_t elapsed; unsigned out_perc = 0; - unsigned out_speed = 0; + unsigned out_size_speed = 0; + unsigned out_block_speed = 0; unsigned out_cpu = 0; unsigned out_eta = 0; int out_computed = 0; @@ -4536,7 +4561,11 @@ int state_progress(struct snapraid_state* state, struct snapraid_io* io, block_o /* estimate the speed in MB/s */ if (delta_time != 0) - out_speed = (unsigned)(delta_size / MEGA / delta_time); + out_size_speed = (unsigned)(delta_size / MEGA / delta_time); + + /* estimate the speed in block/s */ + if (delta_pos != 0) + out_block_speed = (unsigned)(delta_pos / delta_time); /* estimate the cpu usage percentage */ if (delta_tick_total != 0) @@ -4556,12 +4585,13 @@ int state_progress(struct snapraid_state* state, struct snapraid_io* io, block_o } if (state->opt.gui) { - log_tag("run:pos:%u:%u:%" PRIu64 ":%u:%u:%u:%u:%" PRIu64 "\n", blockpos, countpos, countsize, out_perc, out_eta, out_speed, out_cpu, (uint64_t)elapsed); + log_tag("run:pos:%u:%u:%" PRIu64 ":%u:%u:%u:%u:%" PRIu64 "\n", blockpos, countpos, countsize, out_perc, out_eta, out_size_speed, out_cpu, (uint64_t)elapsed); log_flush(); } else { msg_bar("%u%%, %u MB", out_perc, (unsigned)(countsize / MEGA)); if (out_computed) { - msg_bar(", %u MB/s", out_speed); + msg_bar(", %u MB/s", out_size_speed); + msg_bar(", %u block/s", out_block_speed); msg_bar(", CPU %u%%", out_cpu); msg_bar(", %u:%02u ETA", out_eta / 60, out_eta % 60); } diff --git a/cmdline/state.h b/cmdline/state.h index cbc1a55..4794758 100644 --- a/cmdline/state.h +++ b/cmdline/state.h @@ -261,7 +261,7 @@ void state_rehash(struct snapraid_state* state); */ #define SCRUB_AUTO -1 /**< Automatic selection. */ #define SCRUB_BAD -2 /**< Scrub only the bad blocks. */ -#define SCRUB_NEW -3 /**< Scub the new blocks. */ +#define SCRUB_NEW -3 /**< Scrub the new blocks. */ #define SCRUB_FULL -4 /**< Scrub everything. */ #define SCRUB_EVEN -5 /**< Even blocks. */ diff --git a/cmdline/stream.c b/cmdline/stream.c index b7bb2eb..f28338f 100644 --- a/cmdline/stream.c +++ b/cmdline/stream.c @@ -112,7 +112,7 @@ int sopen_multi_file(STREAM* s, unsigned i, const char* file) pathcpy(s->handle[i].path, sizeof(s->handle[i].path), file); - /* O_EXCL to be resilent ensure to always create a new file and not use a stale link to the original file */ + /* O_EXCL to be resilient ensure to always create a new file and not use a stale link to the original file */ f = open(file, O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_SEQUENTIAL, 0600); if (f == -1) { /* LCOV_EXCL_START */ @@ -363,7 +363,7 @@ int sgettok(STREAM* f, char* str, int size) break; } if (c == '\n') { - /* remove ending carrige return to support the Windows CR+LF format */ + /* remove ending carriage return to support the Windows CR+LF format */ if (i != str && i[-1] == '\r') --i; sungetc(c, f); @@ -429,7 +429,7 @@ int sgetline(STREAM* f, char* str, int size) while (1) { c = *pos++; if (c == '\n') { - /* remove ending carrige return to support the Windows CR+LF format */ + /* remove ending carriage return to support the Windows CR+LF format */ if (i != str && i[-1] == '\r') --i; --pos; @@ -455,7 +455,7 @@ int sgetline(STREAM* f, char* str, int size) /* LCOV_EXCL_STOP */ } if (c == '\n') { - /* remove ending carrige return to support the Windows CR+LF format */ + /* remove ending carriage return to support the Windows CR+LF format */ if (i != str && i[-1] == '\r') --i; sungetc(c, f); diff --git a/cmdline/stream.h b/cmdline/stream.h index 35b941f..6ec3391 100644 --- a/cmdline/stream.h +++ b/cmdline/stream.h @@ -28,7 +28,7 @@ * * It's not a constant for testing purpose. */ -unsigned STREAM_SIZE; +extern unsigned STREAM_SIZE; #define STREAM_STATE_READ 0 /**< The stream is in a normal state of read. */ #define STREAM_STATE_WRITE 1 /**< The stream is in a normal state of write. */ diff --git a/cmdline/support.c b/cmdline/support.c index 80dfa5c..16d0229 100644 --- a/cmdline/support.c +++ b/cmdline/support.c @@ -79,6 +79,7 @@ void lock_done(void) /* print */ int msg_level = 0; +FILE* stdlog = 0; /* * Note that in the following functions we always flush both @@ -811,7 +812,7 @@ int mkancestor(const char* file) } #ifdef _WIN32 - /* if it's a drive specificaion like "C:" */ + /* if it's a drive specification like "C:" */ if (isalpha(dir[0]) && dir[1] == ':' && dir[2] == 0) { /* nothing more to do */ return 0; @@ -1236,7 +1237,7 @@ int advise_read(struct advise_struct* advise, int f, data_off_t offset, data_off * non-blocking and do this work in a workqueue (or via some kind of * callback/continuation scheme). My worry is just doing this if a user * application does something crazy, like request gigabytes and gigabytes - * of readahead, and then repents of their craziness, there should be a + * of readahead, and then repented of their craziness, there should be a * way of cancelling the readahead request. Today, the user can just * kill the application. But if we simply shove the work to a kernel * thread, it becomes a lot harder to cancel the readahead request. We'd @@ -1632,16 +1633,16 @@ void thread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) /** * Implementation note about conditional variables. * - * The conditional variables can be signaled inside or ouside the mutex, - * what is better it's debatable but in general doing that ouside the mutex, + * The conditional variables can be signaled inside or outside the mutex, + * what is better it's debatable but in general doing that outside the mutex, * reduces the number of context switches. * - * But when when testing with helgrind and drd, this disallows such tools to + * But when testing with helgrind and drd, this disallows such tools to * to see the dependency between the signal and the wait. * * To avoid it we signal everything inside the mutex. And we do this in both - * test mode (with CHERCKER defined) and release mode (CHECKER not defined), - * to be on the safe side and avoid any difference in beaviour between test and + * test mode (with CHECKER defined) and release mode (CHECKER not defined), + * to be on the safe side and avoid any difference in behaviour between test and * release. * * Here some interesting discussion: diff --git a/cmdline/support.h b/cmdline/support.h index 3b75b38..e7e76b5 100644 --- a/cmdline/support.h +++ b/cmdline/support.h @@ -109,7 +109,7 @@ void log_flush(void); /** * Pointer to log function. */ -typedef void fptr(const char* format, ...); +typedef void fptr(const char* format, ...) __attribute__((format(attribute_printf, 1, 2))); /****************************************************************************/ /* message */ @@ -415,7 +415,7 @@ int smartctl_flush(FILE* f, const char* file, const char* name); * * Ensure to change that before starting any thread. */ -int thread_cond_signal_outside; +extern int thread_cond_signal_outside; /** * Thread wrappers to handle error conditions. diff --git a/cmdline/sync.c b/cmdline/sync.c index 0d12590..96a23c8 100644 --- a/cmdline/sync.c +++ b/cmdline/sync.c @@ -1016,7 +1016,7 @@ static int state_sync_process(struct snapraid_state* state, struct snapraid_pari } /* if we have only silent errors we can try to fix them on-the-fly */ - /* note the the fix is not written to disk, but used only to */ + /* note the fix is not written to disk, but used only to */ /* compute the new parity */ if (!error_on_this_block && !io_error_on_this_block && silent_error_on_this_block) { unsigned failed_mac; @@ -1536,7 +1536,7 @@ int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t data_off_t out_size; parity_size(&parity_handle[l], &out_size); parity_overflow(state, out_size); - log_fatal("WARNING! Without an usable %s file, it isn't possible to sync.\n", lev_name(l)); + log_fatal("WARNING! Without a usable %s file, it isn't possible to sync.\n", lev_name(l)); exit(EXIT_FAILURE); /* LCOV_EXCL_STOP */ } diff --git a/cmdline/unix.c b/cmdline/unix.c index 351cfba..2b897fe 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -632,7 +632,7 @@ int filephy(const char* path, uint64_t size, uint64_t* physical) /* In this way we keep them in the directory traversal order */ /* that at least keeps files in the same directory together. */ /* Note also that in newer file-system with snapshot, like ZFS, */ - /* the inode doesn't represent evenmore the disk position, because files */ + /* the inode doesn't represent even more the disk position, because files */ /* are not overwritten in place, but rewritten in another location */ /* of the disk. */ *physical = FILEPHY_UNREPORTED_OFFSET; diff --git a/cmdline/unix.h b/cmdline/unix.h index 8b190ce..62da33a 100644 --- a/cmdline/unix.h +++ b/cmdline/unix.h @@ -59,7 +59,7 @@ int dirent_hidden(struct dirent* dd); const char* stat_desc(struct stat* st); /** - * Return the aligment requirement for direct IO. + * Return the alignment requirement for direct IO. */ size_t direct_size(void); diff --git a/cmdline/util.c b/cmdline/util.c index 1a35b85..7de2bab 100644 --- a/cmdline/util.c +++ b/cmdline/util.c @@ -470,8 +470,24 @@ static inline uint64_t util_rotl64(uint64_t x, int8_t r) return (x << r) | (x >> (64 - r)); } +/* + * Rotate right. + * In x86/x64 they are optimized with a single assembler instruction. + */ +#if 0 /* unused */ +static inline uint32_t util_rotr32(uint32_t x, int8_t r) +{ + return (x >> r) | (x << (32 - r)); +} +#endif +static inline uint64_t util_rotr64(uint64_t x, int8_t r) +{ + return (x >> r) | (x << (64 - r)); +} + + /** - * Swap endianess. + * Swap endianness. * They are needed only if BigEndian. */ #if defined(__GNUC__) @@ -502,6 +518,18 @@ static inline uint64_t util_swap64(uint64_t v) } #endif +static inline uint8_t util_read8(const void* void_ptr) +{ + const uint8_t* ptr = void_ptr; + return ptr[0]; +} + +static inline uint16_t util_read16(const void* void_ptr) +{ + const uint8_t* ptr = void_ptr; + return ptr[0] + (ptr[1] << 8); +} + static inline uint32_t util_read32(const void* ptr) { uint32_t v; @@ -543,6 +571,7 @@ static inline void util_write64(void* ptr, uint64_t v) #include "murmur3.c" #include "spooky2.c" +#include "metro.c" void memhash(unsigned kind, const unsigned char* seed, void* digest, const void* src, size_t size) { @@ -553,6 +582,9 @@ void memhash(unsigned kind, const unsigned char* seed, void* digest, const void* case HASH_SPOOKY2 : SpookyHash128(src, size, seed, digest); break; + case HASH_METRO : + MetroHash128(src, size, seed, digest); + break; default : /* LCOV_EXCL_START */ log_fatal("Internal inconsistency in hash function %u\n", kind); @@ -568,6 +600,7 @@ const char* hash_config_name(unsigned kind) case HASH_UNDEFINED : return "undefined"; case HASH_MURMUR3 : return "murmur3"; case HASH_SPOOKY2 : return "spooky2"; + case HASH_METRO : return "metro"; default : /* LCOV_EXCL_START */ return "unknown"; diff --git a/cmdline/util.h b/cmdline/util.h index 1661a9d..8717a14 100644 --- a/cmdline/util.h +++ b/cmdline/util.h @@ -161,7 +161,7 @@ static inline uint32_t crc32c_plain(uint32_t crc, const unsigned char* ptr, unsi /** * Compute the CRC-32 (Castagnoli) */ -uint32_t (*crc32c)(uint32_t crc, const unsigned char* ptr, unsigned size); +extern uint32_t (*crc32c)(uint32_t crc, const unsigned char* ptr, unsigned size); /** * Internal entry points for testing. @@ -188,6 +188,7 @@ void crc32c_init(void); #define HASH_UNDEFINED 0 #define HASH_MURMUR3 1 #define HASH_SPOOKY2 2 +#define HASH_METRO 3 /** * Compute the HASH of a memory block. diff --git a/config.h.in b/config.h.in index 2c06e18..de1555e 100644 --- a/config.h.in +++ b/config.h.in @@ -224,6 +224,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MKDEV_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MOUNT_H @@ -240,6 +243,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SYSMACROS_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H @@ -258,14 +264,6 @@ /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF -/* Define to 1 if `major', `minor', and `makedev' are declared in . - */ -#undef MAJOR_IN_MKDEV - -/* Define to 1 if `major', `minor', and `makedev' are declared in - . */ -#undef MAJOR_IN_SYSMACROS - /* Define to 1 if assertions should be disabled. */ #undef NDEBUG diff --git a/configure b/configure index 62f8255..6580ed5 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for snapraid 11.3. +# Generated by GNU Autoconf 2.69 for snapraid 11.5. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. @@ -577,8 +577,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='snapraid' PACKAGE_TARNAME='snapraid' -PACKAGE_VERSION='11.3' -PACKAGE_STRING='snapraid 11.3' +PACKAGE_VERSION='11.5' +PACKAGE_STRING='snapraid 11.5' PACKAGE_BUGREPORT='' PACKAGE_URL='http://www.snapraid.it' @@ -1304,7 +1304,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures snapraid 11.3 to adapt to many kinds of systems. +\`configure' configures snapraid 11.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1374,7 +1374,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of snapraid 11.3:";; + short | recursive ) echo "Configuration of snapraid 11.5:";; esac cat <<\_ACEOF @@ -1496,7 +1496,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -snapraid configure 11.3 +snapraid configure 11.5 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2102,7 +2102,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by snapraid $as_me 11.3, which was +It was created by snapraid $as_me 11.5, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2965,7 +2965,7 @@ fi # Define the identity of the package. PACKAGE='snapraid' - VERSION='11.3' + VERSION='11.5' cat >>confdefs.h <<_ACEOF @@ -4657,6 +4657,22 @@ $as_echo "no" >&6; } fi rm -f conftest* +# This the new default for gcc 10 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC-cc} accepts -fno-common" >&5 +$as_echo_n "checking whether ${CC-cc} accepts -fno-common... " >&6; } +echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -c -fno-common conftest.c 2>&1`"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + CFLAGS="$CFLAGS -fno-common" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +fi +rm -f conftest* + # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : @@ -5115,56 +5131,6 @@ $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether sys/types.h defines makedev" >&5 -$as_echo_n "checking whether sys/types.h defines makedev... " >&6; } -if ${ac_cv_header_sys_types_h_makedev+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -int -main () -{ -return makedev(0, 0); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_header_sys_types_h_makedev=yes -else - ac_cv_header_sys_types_h_makedev=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_sys_types_h_makedev" >&5 -$as_echo "$ac_cv_header_sys_types_h_makedev" >&6; } - -if test $ac_cv_header_sys_types_h_makedev = no; then -ac_fn_c_check_header_mongrel "$LINENO" "sys/mkdev.h" "ac_cv_header_sys_mkdev_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mkdev_h" = xyes; then : - -$as_echo "#define MAJOR_IN_MKDEV 1" >>confdefs.h - -fi - - - - if test $ac_cv_header_sys_mkdev_h = no; then - ac_fn_c_check_header_mongrel "$LINENO" "sys/sysmacros.h" "ac_cv_header_sys_sysmacros_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_sysmacros_h" = xyes; then : - -$as_echo "#define MAJOR_IN_SYSMACROS 1" >>confdefs.h - -fi - - - fi -fi - for ac_header in fcntl.h stddef.h stdint.h stdlib.h string.h limits.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` @@ -5204,7 +5170,7 @@ fi done -for ac_header in sys/file.h sys/ioctl.h sys/vfs.h sys/statfs.h sys/param.h sys/mount.h +for ac_header in sys/file.h sys/ioctl.h sys/vfs.h sys/statfs.h sys/param.h sys/mount.h sys/sysmacros.h sys/mkdev.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -7373,7 +7339,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by snapraid $as_me 11.3, which was +This file was extended by snapraid $as_me 11.5, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -7436,7 +7402,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -snapraid config.status 11.3 +snapraid config.status 11.5 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 6486114..713a4cd 100644 --- a/configure.ac +++ b/configure.ac @@ -17,11 +17,13 @@ AC_CHECK_PROG([SDE],[sde],[sde],[]) AC_CHECK_PROG([ADVD2],[advd2],[advd2],[]) AM_CONDITIONAL(HAVE_ADVD2, [test x"$ADVD2" != x]) -dnl Compiler option to improve stacktrace +dnl Options to improve stacktrace AC_CHECK_CC_OPT([-fno-omit-frame-pointer], CFLAGS="$CFLAGS -fno-omit-frame-pointer", []) AC_CHECK_CC_OPT([-fno-inline-functions-called-once], CFLAGS="$CFLAGS -fno-inline-functions-called-once", []) AC_CHECK_CC_OPT([-fno-inline-small-functions], CFLAGS="$CFLAGS -fno-inline-small-functions", []) AC_CHECK_CC_OPT([-rdynamic], CFLAGS="$CFLAGS -rdynamic", []) +# This the new default for gcc 10 +AC_CHECK_CC_OPT([-fno-common], CFLAGS="$CFLAGS -fno-common", []) dnl Checks for system. AC_SYS_LARGEFILE @@ -31,11 +33,10 @@ AC_HEADER_ASSERT AC_HEADER_DIRENT AC_HEADER_TIME AC_HEADER_SYS_WAIT -AC_HEADER_MAJOR AC_CHECK_HEADERS([fcntl.h stddef.h stdint.h stdlib.h string.h limits.h]) AC_CHECK_HEADERS([unistd.h getopt.h fnmatch.h io.h inttypes.h byteswap.h]) AC_CHECK_HEADERS([pthread.h math.h]) -AC_CHECK_HEADERS([sys/file.h sys/ioctl.h sys/vfs.h sys/statfs.h sys/param.h sys/mount.h]) +AC_CHECK_HEADERS([sys/file.h sys/ioctl.h sys/vfs.h sys/statfs.h sys/param.h sys/mount.h sys/sysmacros.h sys/mkdev.h]) AC_CHECK_HEADERS([linux/fiemap.h linux/fs.h mach/mach_time.h execinfo.h]) dnl Checks for typedefs, structures, and compiler characteristics. diff --git a/raid/check.c b/raid/check.c index 9bed933..d56a150 100644 --- a/raid/check.c +++ b/raid/check.c @@ -36,7 +36,7 @@ * @ip[] Vector of @nv indexes of the valid parity blocks. * The indexes start from 0. They must be in order. * @nd Number of data blocks. - * @size Size of the blocks pointed by @v. It must be a multipler of 64. + * @size Size of the blocks pointed by @v. It must be a multiplier of 64. * @v Vector of pointers to the blocks of data and parity. * It has (@nd + @ip[@nv - 1] + 1) elements. The starting elements are the * blocks for data, following with the parity blocks. diff --git a/raid/helper.h b/raid/helper.h index bf68288..a663efd 100644 --- a/raid/helper.h +++ b/raid/helper.h @@ -23,7 +23,7 @@ * * @n Number of integers currently in the vector. * @v Vector of integers already sorted. - * It must have extra space for the new elemet at the end. + * It must have extra space for the new element at the end. * @i Value to insert. */ void raid_insert(int n, int *v, int i); diff --git a/raid/internal.h b/raid/internal.h index 4465cb9..f8d3c78 100644 --- a/raid/internal.h +++ b/raid/internal.h @@ -174,7 +174,7 @@ void raid_recX_avx2(int nr, int *id, int *ip, int nd, size_t size, void **vv); /* * Internal naming. * - * These are intented to provide access for testing. + * These are intended to provide access for testing. */ const char *raid_gen1_tag(void); const char *raid_gen2_tag(void); @@ -263,7 +263,7 @@ static __always_inline void raid_avx_end(void) raid_sse_end(); /* reset the upper part of the ymm registers */ - /* to avoid the 70 clocks penality on the next */ + /* to avoid the 70 clocks penalty on the next */ /* xmm register use */ asm volatile ("vzeroupper" : : : "memory"); } diff --git a/raid/memory.h b/raid/memory.h index de00614..53a428a 100644 --- a/raid/memory.h +++ b/raid/memory.h @@ -45,7 +45,7 @@ * gen2 6814 [MB/s] * genz 3033 [MB/s] * - * These are the results with displacement resulting in improvments + * These are the results with displacement resulting in improvements * in the order of 20% or more: * * sse2 diff --git a/raid/raid.c b/raid/raid.c index 3052675..ebdfd17 100644 --- a/raid/raid.c +++ b/raid/raid.c @@ -63,11 +63,11 @@ * computation of triple parity using power coefficients. * * Another important property of the Cauchy matrix is that we can setup - * the first two rows with coeffients equal at the RAID5 and RAID6 approach - * decribed, resulting in a compatible extension, and requiring SSSE3 + * the first two rows with coefficients equal at the RAID5 and RAID6 approach + * described, resulting in a compatible extension, and requiring SSSE3 * or AVX2 instructions only if triple parity or beyond is used. * - * The matrix is also adjusted, multipling each row by a constant factor + * The matrix is also adjusted, multiplying each row by a constant factor * to make the first column of all 1, to optimize the computation for * the first disk. * @@ -147,7 +147,7 @@ * "raid/test/speedtest.c" program. * * For comparison, the triple parity computation using the power - * coeffients "1,2,2^-1" is only a little faster than the one based on + * coefficients "1,2,2^-1" is only a little faster than the one based on * the Cauchy matrix if SSSE3 or AVX2 is present. * * int8 int32 int64 sse2 ssse3 avx2 @@ -205,12 +205,12 @@ void raid_zero(void *zero) * All these functions give the guarantee that parities are written * in order. First parity P, then parity Q, and so on. * This allows to specify the same memory buffer for multiple parities - * knowning that you'll get the latest written one. + * knowing that you'll get the latest written one. * This characteristic is used by the raid_delta_gen() function to * avoid to damage unused parities in recovering. * * @nd Number of data blocks - * @size Size of the blocks pointed by @v. It must be a multipler of 64. + * @size Size of the blocks pointed by @v. It must be a multiplier of 64. * @v Vector of pointers to the blocks of data and parity. * It has (@nd + #parities) elements. The starting elements are the blocks * for data, following with the parity blocks. @@ -335,7 +335,7 @@ void raid_delta_gen(int nr, int *id, int *ip, int nd, size_t size, void **v) } else { /* * Unused parities are going to be rewritten with - * not significative data, becase we don't have + * not significative data, because we don't have * functions able to compute only a subset of * parities. * @@ -483,7 +483,7 @@ void raid_rec2of2_int8(int *id, int *ip, int nd, size_t size, void **vv) * The indexes start from 0. They must be in order. * @nd Number of data blocks. * @np Number of parity blocks. - * @size Size of the blocks pointed by @v. It must be a multipler of 64. + * @size Size of the blocks pointed by @v. It must be a multiplier of 64. * @v Vector of pointers to the blocks of data and parity. * It has (@nd + @np) elements. The starting elements are the blocks * for data, following with the parity blocks. diff --git a/raid/tables.c b/raid/tables.c index 4903502..7828956 100644 --- a/raid/tables.c +++ b/raid/tables.c @@ -13662,8 +13662,8 @@ const uint8_t __aligned(256) raid_gfcauchypshufb[251][4][2][16] = /** * PSHUFB tables for generic multiplication. * - * Indexes are [MULTIPLER][LH]. - * Where MULTIPLER is from 0 to 255, LH from 0 to 1. + * Indexes are [MULTIPLIER][LH]. + * Where MULTIPLIER is from 0 to 255, LH from 0 to 1. */ const uint8_t __aligned(256) raid_gfmulpshufb[256][2][16] = { diff --git a/raid/test/Makefile b/raid/test/Makefile index 229d5ad..6423fd1 100644 --- a/raid/test/Makefile +++ b/raid/test/Makefile @@ -3,7 +3,7 @@ # # selftest - Runs the same selftest and speedtest executed at the module startup. # fulltest - Runs a more extensive test that checks all the built-in functions. -# speetest - Runs a more complete speed test. +# speedtest - Runs a more complete speed test. # invtest - Runs an extensive matrix inversion test of all the 377.342.351.231 # possible square submatrices of the Cauchy matrix used. # covtest - Runs a coverage test. diff --git a/snapraid.1 b/snapraid.1 index 0fb9b7b..ce7aa9b 100644 --- a/snapraid.1 +++ b/snapraid.1 @@ -79,6 +79,9 @@ Beside the ability to recover from disk failures, other features of SnapRAID are: .PD 0 .IP \(bu +You can use disk already filled with files, without the need to +reformat them. You will access them like now. +.IP \(bu All your data is hashed to ensure data integrity and to avoid silent corruption. .IP \(bu @@ -89,8 +92,6 @@ All the data in the other disks is safe. If you accidentally delete some files in a disk, you can recover them. .IP \(bu -You can start with already filled disks. -.IP \(bu The disks can have different sizes. .IP \(bu You can add disks at any time. @@ -98,7 +99,7 @@ You can add disks at any time. It doesn\'t lock\-in your data. You can stop using SnapRAID at any time without the need to reformat or move data. .IP \(bu -To access a file, a single disk needs to spin, saving power and +To access a file, only a single disk needs to spin, saving power and producing less noise. .PD .PP @@ -686,7 +687,7 @@ run \[dq]sync\[dq]. Later modifications are not taken into account. If bad blocks were detected, their block numbers are listed. To fix them, you can use the \[dq]fix \-e\[dq] command. .PP -It also shows a graph representing the the last time each block +It also shows a graph representing the last time each block was scrubbed or synced. Scrubbed blocks are shown with \'*\', blocks synced but not yet scrubbed with \'o\'. .PP @@ -889,7 +890,7 @@ Use the filter options to select a subset of files or disks to operate on. To only fix the blocks marked bad during \[dq]sync\[dq] and \[dq]scrub\[dq], use the \-e, \-\-filter\-error option. As difference from other filter options, with this one the fixes are -applied only to files that are not modified from the the latest \[dq]sync\[dq]. +applied only to files that are not modified from the latest \[dq]sync\[dq]. .PP All the files that cannot be fixed are renamed adding the \[dq].unrecoverable\[dq] extension. diff --git a/snapraid.d b/snapraid.d index 82ccdb5..0cc6650 100644 --- a/snapraid.d +++ b/snapraid.d @@ -31,6 +31,8 @@ Description Beside the ability to recover from disk failures, other features of SnapRAID are: + * You can use disk already filled with files, without the need to + reformat them. You will access them like now. * All your data is hashed to ensure data integrity and to avoid silent corruption. * If the failed disks are too many to allow a recovery, @@ -38,12 +40,11 @@ Description All the data in the other disks is safe. * If you accidentally delete some files in a disk, you can recover them. - * You can start with already filled disks. * The disks can have different sizes. * You can add disks at any time. * It doesn't lock-in your data. You can stop using SnapRAID at any time without the need to reformat or move data. - * To access a file, a single disk needs to spin, saving power and + * To access a file, only a single disk needs to spin, saving power and producing less noise. The official site of SnapRAID is: @@ -400,7 +401,7 @@ Commands If bad blocks were detected, their block numbers are listed. To fix them, you can use the "fix -e" command. - It also shows a graph representing the the last time each block + It also shows a graph representing the last time each block was scrubbed or synced. Scrubbed blocks are shown with '*', blocks synced but not yet scrubbed with 'o'. @@ -577,7 +578,7 @@ Commands To only fix the blocks marked bad during "sync" and "scrub", use the -e, --filter-error option. As difference from other filter options, with this one the fixes are - applied only to files that are not modified from the the latest "sync". + applied only to files that are not modified from the latest "sync". All the files that cannot be fixed are renamed adding the ".unrecoverable" extension. diff --git a/snapraid.txt b/snapraid.txt index 9621e04..78cfb35 100644 --- a/snapraid.txt +++ b/snapraid.txt @@ -38,6 +38,8 @@ big files that rarely change. Beside the ability to recover from disk failures, other features of SnapRAID are: +* You can use disk already filled with files, without the need to + reformat them. You will access them like now. * All your data is hashed to ensure data integrity and to avoid silent corruption. * If the failed disks are too many to allow a recovery, @@ -45,12 +47,11 @@ features of SnapRAID are: All the data in the other disks is safe. * If you accidentally delete some files in a disk, you can recover them. -* You can start with already filled disks. * The disks can have different sizes. * You can add disks at any time. * It doesn't lock-in your data. You can stop using SnapRAID at any time without the need to reformat or move data. -* To access a file, a single disk needs to spin, saving power and +* To access a file, only a single disk needs to spin, saving power and producing less noise. The official site of SnapRAID is: @@ -426,7 +427,7 @@ run "sync". Later modifications are not taken into account. If bad blocks were detected, their block numbers are listed. To fix them, you can use the "fix -e" command. -It also shows a graph representing the the last time each block +It also shows a graph representing the last time each block was scrubbed or synced. Scrubbed blocks are shown with '*', blocks synced but not yet scrubbed with 'o'. @@ -617,7 +618,7 @@ Use the filter options to select a subset of files or disks to operate on. To only fix the blocks marked bad during "sync" and "scrub", use the -e, --filter-error option. As difference from other filter options, with this one the fixes are -applied only to files that are not modified from the the latest "sync". +applied only to files that are not modified from the latest "sync". All the files that cannot be fixed are renamed adding the ".unrecoverable" extension. diff --git a/tommyds/tommychain.h b/tommyds/tommychain.h index 12d2514..4ff3f1a 100644 --- a/tommyds/tommychain.h +++ b/tommyds/tommychain.h @@ -114,7 +114,7 @@ tommy_inline void tommy_chain_merge(tommy_chain* first, tommy_chain* second, tom /** * Merges two chains managing special degenerated cases. - * It's funtionally equivalent at tommy_chain_merge() but faster with already ordered chains. + * It's functionally equivalent at tommy_chain_merge() but faster with already ordered chains. */ tommy_inline void tommy_chain_merge_degenerated(tommy_chain* first, tommy_chain* second, tommy_compare_func* cmp) { @@ -153,7 +153,7 @@ tommy_inline void tommy_chain_mergesort(tommy_chain* chain, tommy_compare_func* /* * Bit buckets of chains. * Each bucket contains 2^i nodes or it's empty. - * The chain at address TOMMY_BIT_MAX is an independet variable operating as "carry". + * The chain at address TOMMY_BIT_MAX is an independent variable operating as "carry". * We keep it in the same "bit" vector to avoid reports from the valgrind tool sgcheck. */ tommy_chain bit[TOMMY_SIZE_BIT + 1]; diff --git a/tommyds/tommyhash.c b/tommyds/tommyhash.c index cc7495d..71c4ef3 100644 --- a/tommyds/tommyhash.c +++ b/tommyds/tommyhash.c @@ -231,7 +231,7 @@ tommy_uint32_t tommy_strhash_u32(tommy_uint64_t init_val, const void* void_key) key += 12; } - /* for lengths that are multiplers of 12 we already have called mix */ + /* for lengths that are multipliers of 12 we already have called mix */ /* this is different than the original lookup3 and the result won't match */ tommy_final(a, b, c); diff --git a/tommyds/tommyhash.h b/tommyds/tommyhash.h index 50d595c..e9bdba0 100644 --- a/tommyds/tommyhash.h +++ b/tommyds/tommyhash.h @@ -52,7 +52,7 @@ * \param void_key Pointer to the data to hash. * \param key_len Size of the data to hash. * \note - * This function is endianess independent. + * This function is endianness independent. * \return The hash value of 32 bits. */ tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tommy_size_t key_len); @@ -72,14 +72,14 @@ tommy_uint32_t tommy_hash_u32(tommy_uint32_t init_val, const void* void_key, tom * \param void_key Pointer to the data to hash. * \param key_len Size of the data to hash. * \note - * This function is endianess independent. + * This function is endianness independent. * \return The hash value of 64 bits. */ tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tommy_size_t key_len); /** * String hash function with a 32 bits result. - * Implementation is based on the the Robert Jenkins "lookup3" hash 32 bits version, + * Implementation is based on Robert Jenkins "lookup3" hash 32 bits version, * from http://www.burtleburtle.net/bob/hash/doobs.html, function hashlittle(). * * This hash is designed to handle strings with an unknown length. If you @@ -90,7 +90,7 @@ tommy_uint64_t tommy_hash_u64(tommy_uint64_t init_val, const void* void_key, tom * Use 0 if not relevant. * \param void_key Pointer to the string to hash. It has to be 0 terminated. * \note - * This function is endianess independent. + * This function is endianness independent. * \return The hash value of 32 bits. */ tommy_uint32_t tommy_strhash_u32(tommy_uint64_t init_val, const void* void_key); diff --git a/tommyds/tommyhashdyn.h b/tommyds/tommyhashdyn.h index 73baba9..0ea042f 100644 --- a/tommyds/tommyhashdyn.h +++ b/tommyds/tommyhashdyn.h @@ -92,7 +92,7 @@ * * To iterate over all the elements in the hashtable with the same key, you have to * use tommy_hashdyn_bucket() and follow the tommy_node::next pointer until NULL. - * You have also to check explicitely for the key, as the bucket may contains + * You have also to check explicitly for the key, as the bucket may contains * different keys. * * \code diff --git a/tommyds/tommylist.h b/tommyds/tommylist.h index 42ef3ad..f70ad45 100644 --- a/tommyds/tommylist.h +++ b/tommyds/tommylist.h @@ -28,7 +28,7 @@ /** \file * Double linked list for collisions into hashtables. * - * This list is a double linked list mainly targetted for handling collisions + * This list is a double linked list mainly targeted for handling collisions * into an hashtables, but useable also as a generic list. * * The main feature of this list is to require only one pointer to represent the @@ -294,7 +294,7 @@ tommy_inline void tommy_list_concat(tommy_list* first, tommy_list* second) * It's a stable merge sort with O(N*log(N)) worst complexity. * It's faster on degenerated cases like partially ordered lists. * \param cmp Compare function called with two elements. - * The function should return <0 if the first element is less than the second, ==0 if equal, and >0 if greather. + * The function should return <0 if the first element is less than the second, ==0 if equal, and >0 if greater. */ void tommy_list_sort(tommy_list* list, tommy_compare_func* cmp); diff --git a/tommyds/tommytree.h b/tommyds/tommytree.h index ada12c0..e56f865 100644 --- a/tommyds/tommytree.h +++ b/tommyds/tommytree.h @@ -33,7 +33,7 @@ * * As difference than other tommy containers, duplicate elements cannot be inserted. * - * To initialize a tree you have to call tommy_tree_init() specifing a comparison + * To initialize a tree you have to call tommy_tree_init() specifying a comparison * function that will define the order in the tree. * * \code @@ -123,7 +123,7 @@ typedef struct tommy_tree_struct { /** * Initializes the tree. - * \param cmp The comparison function that defines the orderin the tree. + * \param cmp The comparison function that defines the order in the tree. */ void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp); diff --git a/tommyds/tommytypes.h b/tommyds/tommytypes.h index 0608b15..8dc206b 100644 --- a/tommyds/tommytypes.h +++ b/tommyds/tommytypes.h @@ -227,7 +227,7 @@ typedef struct tommy_node_struct { * Compare function for elements. * \param obj_a Pointer to the first object to compare. * \param obj_b Pointer to the second object to compare. - * \return <0 if the first element is less than the second, ==0 equal, >0 if greather. + * \return <0 if the first element is less than the second, ==0 equal, >0 if greater. * * This function is like the C strcmp(). *