Merge tag 'upstream/11.5'
Upstream version 11.5
This commit is contained in:
commit
1dd99167db
18
HISTORY
18
HISTORY
@ -1,6 +1,20 @@
|
|||||||
SnapRAID HISTORY
|
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
|
11.3 2018/11
|
||||||
============
|
============
|
||||||
* Fixed handing of Linux devices that have multiple slaves. This affects
|
* 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,
|
A workaround was to just run 'sync' one time with the -N,
|
||||||
--force-nocopy option to disable the copy detection.
|
--force-nocopy option to disable the copy detection.
|
||||||
* Restored the -O2 optimization option for Windows binaries, as -Og has
|
* 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
|
9.2 2016/01
|
||||||
===========
|
===========
|
||||||
@ -412,7 +426,7 @@ SnapRAID HISTORY
|
|||||||
and Opteron.
|
and Opteron.
|
||||||
* Faster RAID5 and RAID6 implementation for ARM 64 bit CPUs.
|
* Faster RAID5 and RAID6 implementation for ARM 64 bit CPUs.
|
||||||
* If a silent error is found during a "sync" command, directly marks
|
* 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.
|
process.
|
||||||
* Sort files by inode when listing the directory. This improves
|
* Sort files by inode when listing the directory. This improves
|
||||||
the scanning performance.
|
the scanning performance.
|
||||||
|
@ -83,6 +83,7 @@ noinst_HEADERS = \
|
|||||||
cmdline/murmur3test.c \
|
cmdline/murmur3test.c \
|
||||||
cmdline/spooky2.c \
|
cmdline/spooky2.c \
|
||||||
cmdline/spooky2test.c \
|
cmdline/spooky2test.c \
|
||||||
|
cmdline/metro.c \
|
||||||
cmdline/fnmatch.h \
|
cmdline/fnmatch.h \
|
||||||
cmdline/import.h \
|
cmdline/import.h \
|
||||||
cmdline/search.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
|
CHECKFLAGS_COMMON = --test-skip-device --test-skip-self --test-force-progress --no-warnings --test-parity-limit=3333333
|
||||||
|
|
||||||
# --test-force-order-alpha
|
# --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.
|
# the inode, physical location, and dir order assigned by the OS.
|
||||||
CHECKFLAGS_ALPHA = $(CHECKFLAGS_COMMON) --test-force-order-alpha
|
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
|
$(FAILENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-run "rm bench/disk1/RUN-RM" --test-expect-failure sync
|
||||||
echo RUN > bench/disk1/RUN-CHMOD
|
echo RUN > bench/disk1/RUN-CHMOD
|
||||||
if HAVE_POSIX
|
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 \
|
if [[ $$EUID -ne 0 ]]; then \
|
||||||
$(FAILENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-run "chmod a-r bench/disk1/RUN-CHMOD" --test-expect-failure sync; \
|
$(FAILENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) --test-run "chmod a-r bench/disk1/RUN-CHMOD" --test-expect-failure sync; \
|
||||||
fi
|
fi
|
||||||
|
@ -429,6 +429,7 @@ noinst_HEADERS = \
|
|||||||
cmdline/murmur3test.c \
|
cmdline/murmur3test.c \
|
||||||
cmdline/spooky2.c \
|
cmdline/spooky2.c \
|
||||||
cmdline/spooky2test.c \
|
cmdline/spooky2test.c \
|
||||||
|
cmdline/metro.c \
|
||||||
cmdline/fnmatch.h \
|
cmdline/fnmatch.h \
|
||||||
cmdline/import.h \
|
cmdline/import.h \
|
||||||
cmdline/search.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
|
CHECKFLAGS_COMMON = --test-skip-device --test-skip-self --test-force-progress --no-warnings --test-parity-limit=3333333
|
||||||
|
|
||||||
# --test-force-order-alpha
|
# --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.
|
# the inode, physical location, and dir order assigned by the OS.
|
||||||
CHECKFLAGS_ALPHA = $(CHECKFLAGS_COMMON) --test-force-order-alpha
|
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@ 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@ $(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
|
@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@ 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@ $(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
|
@HAVE_POSIX_TRUE@@HAVE_THREAD_CHECKER_FALSE@ fi
|
||||||
|
5
README
5
README
@ -11,6 +11,8 @@ have a lot of big files that rarely change.
|
|||||||
Beside the ability to recover from disk failures, the other
|
Beside the ability to recover from disk failures, the other
|
||||||
features of SnapRAID are:
|
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
|
* All your data is hashed to ensure data integrity and to avoid
|
||||||
silent corruption.
|
silent corruption.
|
||||||
* If the failed disks are too many to allow a recovery,
|
* 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.
|
All the data in the other disks is safe.
|
||||||
* If you accidentally delete some files in a disk, you can
|
* If you accidentally delete some files in a disk, you can
|
||||||
recover them.
|
recover them.
|
||||||
* You can start with already filled disks.
|
|
||||||
* The disks can have different sizes.
|
* The disks can have different sizes.
|
||||||
* You can add disks at any time.
|
* You can add disks at any time.
|
||||||
* It doesn't lock-in your data. You can stop using SnapRAID at any
|
* It doesn't lock-in your data. You can stop using SnapRAID at any
|
||||||
time without the need to reformat or move data.
|
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.
|
producing less noise.
|
||||||
|
|
||||||
The official site of SnapRAID is:
|
The official site of SnapRAID is:
|
||||||
|
12
TODO
12
TODO
@ -25,8 +25,8 @@ with a mono thread implementation with 100.0000 files.
|
|||||||
* Support more parity levels
|
* Support more parity levels
|
||||||
It can be done with a generic computation function, using
|
It can be done with a generic computation function, using
|
||||||
intrinsic for SSSE3 and AVX instructions.
|
intrinsic for SSSE3 and AVX instructions.
|
||||||
It would be intersting to compare performance with the hand-written
|
It would be interesting to compare performance with the hand-written
|
||||||
assembler functions. Eventially we can convert them to use intrinsic also.
|
assembler functions. Eventually we can convert them to use intrinsic also.
|
||||||
https://sourceforge.net/p/snapraid/discussion/1677233/thread/9dbd7581/
|
https://sourceforge.net/p/snapraid/discussion/1677233/thread/9dbd7581/
|
||||||
|
|
||||||
* Extend haspdeep to support the SnapRAID hash :
|
* 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
|
* Allocate parity minimizing concurrent use of it
|
||||||
Each parity allocation should check for a parity
|
Each parity allocation should check for a parity
|
||||||
range with less utilization by other disks.
|
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.
|
is near to fillup the parity partition.
|
||||||
See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/1797bf7d/
|
See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/1797bf7d/
|
||||||
+ This increase the possibility of recovering with multiple failures with not
|
+ 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.
|
- It won't work with disks of different size.
|
||||||
Suppose to have all disks of size N, with only one of size M>N.
|
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,
|
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 fact requiring a total of M parity for the array.
|
||||||
In the end, we cannot avoid that the first biggest disk added is fully
|
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.
|
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 :)
|
A lot of discussions about this feature :)
|
||||||
https://sourceforge.net/p/snapraid/discussion/1677233/thread/b2cd9385/
|
https://sourceforge.net/p/snapraid/discussion/1677233/thread/b2cd9385/
|
||||||
- The only benefit is to distribute better the data. This could help the recovery process,
|
- 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.
|
case.
|
||||||
|
|
||||||
* https://sourceforge.net/p/snapraid/discussion/1677233/thread/2cb97e8a/
|
* 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
|
* Checks if splitting hash/parity computation in 4K pages
|
||||||
can improve speed in sync. That should increase cache locality,
|
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.
|
and if we manage to keep it in the cache, we should save time.
|
||||||
- We now hash first the faster disks, and this could
|
- We now hash first the faster disks, and this could
|
||||||
reduce performance as we'll have to wait for all disks.
|
reduce performance as we'll have to wait for all disks.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
dnl @synopsis AC_CHECK_CC_OPT(flag, ifyes, ifno)
|
dnl @synopsis AC_CHECK_CC_OPT(flag, ifyes, ifno)
|
||||||
dnl
|
dnl
|
||||||
dnl Shows a message as like "checking wether gcc accepts flag ... no"
|
dnl Shows a message as like "checking whether gcc accepts flag ... no"
|
||||||
dnl and executess ifyes or ifno.
|
dnl and executes ifyes or ifno.
|
||||||
|
|
||||||
AC_DEFUN([AC_CHECK_CC_OPT],
|
AC_DEFUN([AC_CHECK_CC_OPT],
|
||||||
[
|
[
|
||||||
|
@ -574,7 +574,7 @@ static int repair(struct snapraid_state* state, int rehash, unsigned pos, unsign
|
|||||||
} else {
|
} else {
|
||||||
log_tag("recover_unsync:%u:%u: Skipped for%s%s\n", pos, n,
|
log_tag("recover_unsync:%u:%u: Skipped for%s%s\n", pos, n,
|
||||||
!something_to_recover ? " nothing to recover" : "",
|
!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];
|
char path[PATH_MAX];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct snapraid_file* file;
|
struct snapraid_file* file;
|
||||||
int unsuccesful = 0;
|
int unsuccessful = 0;
|
||||||
|
|
||||||
file = node->data;
|
file = node->data;
|
||||||
node = node->next; /* next node */
|
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);
|
pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub);
|
||||||
ret = stat(path, &st);
|
ret = stat(path, &st);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
unsuccesful = 1;
|
unsuccessful = 1;
|
||||||
|
|
||||||
log_error("Error stating empty file '%s'. %s.\n", path, strerror(errno));
|
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));
|
log_tag("error:%s:%s: Empty file stat error\n", disk->name, esc_tag(file->sub, esc_buffer));
|
||||||
++error;
|
++error;
|
||||||
} else if (!S_ISREG(st.st_mode)) {
|
} 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));
|
log_tag("error:%s:%s: Empty file error for not regular file\n", disk->name, esc_tag(file->sub, esc_buffer));
|
||||||
++error;
|
++error;
|
||||||
} else if (st.st_size != 0) {
|
} 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);
|
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;
|
++error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fix && unsuccesful) {
|
if (fix && unsuccessful) {
|
||||||
int f;
|
int f;
|
||||||
|
|
||||||
/* create the ancestor directories */
|
/* 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 st;
|
||||||
struct stat stto;
|
struct stat stto;
|
||||||
struct snapraid_link* slink;
|
struct snapraid_link* slink;
|
||||||
int unsuccesful = 0;
|
int unsuccessful = 0;
|
||||||
int unrecoverable = 0;
|
int unrecoverable = 0;
|
||||||
|
|
||||||
slink = node->data;
|
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);
|
pathprint(path, sizeof(path), "%s%s", disk->dir, slink->sub);
|
||||||
ret = stat(path, &st);
|
ret = stat(path, &st);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
unsuccesful = 1;
|
unsuccessful = 1;
|
||||||
|
|
||||||
log_error("Error stating hardlink '%s'. %s.\n", path, strerror(errno));
|
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));
|
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;
|
++error;
|
||||||
} else if (!S_ISREG(st.st_mode)) {
|
} 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));
|
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;
|
++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);
|
pathprint(pathto, sizeof(pathto), "%s%s", disk->dir, slink->linkto);
|
||||||
ret = stat(pathto, &stto);
|
ret = stat(pathto, &stto);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
unsuccesful = 1;
|
unsuccessful = 1;
|
||||||
|
|
||||||
if (errno == ENOENT) {
|
if (errno == ENOENT) {
|
||||||
unrecoverable = 1;
|
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));
|
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;
|
++error;
|
||||||
} else if (!S_ISREG(stto.st_mode)) {
|
} 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));
|
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;
|
++error;
|
||||||
} else if (!unsuccesful && st.st_ino != stto.st_ino) {
|
} else if (!unsuccessful && st.st_ino != stto.st_ino) {
|
||||||
unsuccesful = 1;
|
unsuccessful = 1;
|
||||||
|
|
||||||
log_error("Mismatch hardlink '%s' and '%s'. Different inode.\n", path, pathto);
|
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));
|
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);
|
pathprint(path, sizeof(path), "%s%s", disk->dir, slink->sub);
|
||||||
ret = readlink(path, linkto, sizeof(linkto));
|
ret = readlink(path, linkto, sizeof(linkto));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
unsuccesful = 1;
|
unsuccessful = 1;
|
||||||
|
|
||||||
log_error("Error reading symlink '%s'. %s.\n", path, strerror(errno));
|
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));
|
log_tag("symlink_error:%s:%s: Symlink read error\n", disk->name, esc_tag(slink->sub, esc_buffer));
|
||||||
++error;
|
++error;
|
||||||
} else if (ret >= PATH_MAX) {
|
} else if (ret >= PATH_MAX) {
|
||||||
unsuccesful = 1;
|
unsuccessful = 1;
|
||||||
|
|
||||||
log_error("Error reading symlink '%s'. Symlink too long.\n", path);
|
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));
|
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;
|
linkto[ret] = 0;
|
||||||
|
|
||||||
if (strcmp(linkto, slink->linkto) != 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);
|
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;
|
++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 */
|
/* create the ancestor directories */
|
||||||
ret = mkancestor(path);
|
ret = mkancestor(path);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
@ -1720,7 +1720,7 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
|
|||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
struct stat st;
|
struct stat st;
|
||||||
struct snapraid_dir* dir;
|
struct snapraid_dir* dir;
|
||||||
int unsuccesful = 0;
|
int unsuccessful = 0;
|
||||||
|
|
||||||
dir = node->data;
|
dir = node->data;
|
||||||
node = node->next; /* next node */
|
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);
|
pathprint(path, sizeof(path), "%s%s", disk->dir, dir->sub);
|
||||||
ret = stat(path, &st);
|
ret = stat(path, &st);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
unsuccesful = 1;
|
unsuccessful = 1;
|
||||||
|
|
||||||
log_error("Error stating dir '%s'. %s.\n", path, strerror(errno));
|
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));
|
log_tag("dir_error:%s:%s: Dir stat error\n", disk->name, esc_tag(dir->sub, esc_buffer));
|
||||||
++error;
|
++error;
|
||||||
} else if (!S_ISDIR(st.st_mode)) {
|
} 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));
|
log_tag("dir_error:%s:%s: Dir error for not directory\n", disk->name, esc_tag(dir->sub, esc_buffer));
|
||||||
++error;
|
++error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fix && unsuccesful) {
|
if (fix && unsuccessful) {
|
||||||
/* create the ancestor directories */
|
/* create the ancestor directories */
|
||||||
ret = mkancestor(path);
|
ret = mkancestor(path);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
@ -1973,6 +1973,17 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
parity_ptr[l] = &parity[l];
|
parity_ptr[l] = &parity[l];
|
||||||
|
|
||||||
|
/* 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);
|
ret = parity_create(parity_ptr[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
@ -1989,6 +2000,7 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b
|
|||||||
/* LCOV_EXCL_STOP */
|
/* LCOV_EXCL_STOP */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (!state->opt.auditonly) {
|
} else if (!state->opt.auditonly) {
|
||||||
/* if checking, open the file for reading */
|
/* if checking, open the file for reading */
|
||||||
/* it may fail if the file doesn't exist, in this case we continue to check the files */
|
/* it may fail if the file doesn't exist, in this case we continue to check the files */
|
||||||
@ -2030,16 +2042,28 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b
|
|||||||
/* try to close only if opened */
|
/* try to close only if opened */
|
||||||
for (l = 0; l < state->level; ++l) {
|
for (l = 0; l < state->level; ++l) {
|
||||||
if (parity_ptr[l]) {
|
if (parity_ptr[l]) {
|
||||||
ret = parity_close(parity_ptr[l]);
|
/* if fixing and not excluded, truncate parity not valid */
|
||||||
/* LCOV_EXCL_START */
|
if (fix && !state->parity[l].is_excluded_by_filter) {
|
||||||
|
ret = parity_truncate(parity_ptr[l]);
|
||||||
if (ret == -1) {
|
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]);
|
||||||
|
if (ret == -1) {
|
||||||
|
/* LCOV_EXCL_START */
|
||||||
log_fatal("DANGER! Unexpected close error in %s disk.\n", lev_name(l));
|
log_fatal("DANGER! Unexpected close error in %s disk.\n", lev_name(l));
|
||||||
++error;
|
++error;
|
||||||
/* continue, as we are already exiting */
|
/* continue, as we are already exiting */
|
||||||
}
|
|
||||||
/* LCOV_EXCL_STOP */
|
/* LCOV_EXCL_STOP */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* abort if error are present */
|
/* abort if error are present */
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
|
@ -818,7 +818,7 @@ static void state_smart(unsigned n, tommy_list* low)
|
|||||||
|
|
||||||
/* |<##################################################################72>|####80>| */
|
/* |<##################################################################72>|####80>| */
|
||||||
printf("These values are the probabilities that in the next year you'll have a\n");
|
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("that you regularly scrub, and in case repair, the array in the specified\n");
|
||||||
printf("time.\n");
|
printf("time.\n");
|
||||||
|
|
||||||
|
@ -349,7 +349,7 @@ struct snapraid_disk {
|
|||||||
block_off_t first_free_block;
|
block_off_t first_free_block;
|
||||||
|
|
||||||
int has_volatile_inodes; /**< If the underline file-system has not persistent inodes. */
|
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_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_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. */
|
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
|
* After this call you can use the par2file/par2block operations
|
||||||
* to query the relation.
|
* 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);
|
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
|
* After this call the par2file/par2block operations
|
||||||
* won't find anymore the parity association.
|
* 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);
|
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.
|
* Extract the time information.
|
||||||
* This is the last time when the block was know to be correct.
|
* 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)
|
static inline time_t info_get_time(snapraid_info info)
|
||||||
{
|
{
|
||||||
|
13
cmdline/io.c
13
cmdline/io.c
@ -19,6 +19,19 @@
|
|||||||
|
|
||||||
#include "io.h"
|
#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.
|
* Get the next block position to process.
|
||||||
*/
|
*/
|
||||||
|
20
cmdline/io.h
20
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);
|
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);
|
void io_done(struct snapraid_io* io);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start all the worker threads.
|
* 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,
|
block_off_t blockstart, block_off_t blockmax,
|
||||||
int (*block_is_enabled)(void* arg, block_off_t), void* blockarg);
|
int (*block_is_enabled)(void* arg, block_off_t), void* blockarg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop all the worker threads.
|
* Stop all the worker threads.
|
||||||
*/
|
*/
|
||||||
void (*io_stop)(struct snapraid_io* io);
|
extern void (*io_stop)(struct snapraid_io* io);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Next read position.
|
* Next read position.
|
||||||
@ -332,7 +332,7 @@ void (*io_stop)(struct snapraid_io* io);
|
|||||||
* \param buffer The data buffers to use for this position.
|
* \param buffer The data buffers to use for this position.
|
||||||
* \return The parity 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.
|
* 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.
|
* \param diskcur The position of the data block in the ::handle_map vector.
|
||||||
* \return The completed task.
|
* \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.
|
* 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.
|
* \param levcur The position of the parity block in the ::parity_handle_map vector.
|
||||||
* \return The completed task.
|
* \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.
|
* 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 io InputOutput context.
|
||||||
* \param levcur The position of the parity block in the ::parity_handle_map vector.
|
* \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.
|
* 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 blockcur The parity position to write.
|
||||||
* \param skip Skip the writes, in case parity doesn't need to be updated.
|
* \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.
|
* 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 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.
|
* \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.
|
* 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
|
#endif
|
||||||
|
|
||||||
|
108
cmdline/metro.c
Normal file
108
cmdline/metro.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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]);
|
||||||
|
}
|
||||||
|
|
@ -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!
|
* See: Symlinks in Windows 10!
|
||||||
* https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/#cQG7cx48oGH86lkI.97
|
* 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)
|
if (has_persistent_inode)
|
||||||
*has_persistent_inode = 1;
|
*has_persistent_inode = 1;
|
||||||
|
|
||||||
/* NTFS doesn't syncronize hardlinks metadata */
|
/* NTFS doesn't synchronize hardlinks metadata */
|
||||||
if (has_syncronized_hardlinks)
|
if (has_syncronized_hardlinks)
|
||||||
*has_syncronized_hardlinks = 0;
|
*has_syncronized_hardlinks = 0;
|
||||||
|
|
||||||
|
@ -217,6 +217,9 @@ int parity_create(struct snapraid_parity_handle* handle, const struct snapraid_p
|
|||||||
/* LCOV_EXCL_STOP */
|
/* 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.
|
* If the parity size is not yet set, set it now.
|
||||||
* This happens when expanding the number of parities,
|
* 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 */
|
/* 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -697,6 +704,9 @@ int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_par
|
|||||||
/* LCOV_EXCL_STOP */
|
/* 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.
|
* If the parity size is not yet set, set it now.
|
||||||
* This happens when expanding the number of parities,
|
* This happens when expanding the number of parities,
|
||||||
@ -751,7 +761,7 @@ int parity_sync(struct snapraid_parity_handle* handle)
|
|||||||
ret = fsync(split->f);
|
ret = fsync(split->f);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
/* LCOV_EXCL_START */
|
/* 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;
|
return -1;
|
||||||
/* LCOV_EXCL_STOP */
|
/* LCOV_EXCL_STOP */
|
||||||
}
|
}
|
||||||
@ -761,6 +771,30 @@ int parity_sync(struct snapraid_parity_handle* handle)
|
|||||||
return 0;
|
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)
|
int parity_close(struct snapraid_parity_handle* handle)
|
||||||
{
|
{
|
||||||
unsigned s;
|
unsigned s;
|
||||||
@ -826,6 +860,10 @@ int parity_write(struct snapraid_parity_handle* handle, block_off_t pos, unsigne
|
|||||||
/* LCOV_EXCL_STOP */
|
/* 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);
|
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 */
|
if (write_ret != (ssize_t)block_size) { /* conversion is safe because block_size is always small */
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
@ -867,6 +905,14 @@ int parity_read(struct snapraid_parity_handle* handle, block_off_t pos, unsigned
|
|||||||
/* LCOV_EXCL_STOP */
|
/* 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;
|
count = 0;
|
||||||
do {
|
do {
|
||||||
read_ret = pread(split->f, block_buffer + count, block_size - count, offset + count);
|
read_ret = pread(split->f, block_buffer + count, block_size - count, offset + count);
|
||||||
|
@ -36,6 +36,16 @@ struct snapraid_split_handle {
|
|||||||
*/
|
*/
|
||||||
data_off_t size;
|
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.
|
* Artificial size limit for testing.
|
||||||
* 0 means unlimited.
|
* 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);
|
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.
|
* Close the parity file.
|
||||||
*/
|
*/
|
||||||
|
@ -369,7 +369,7 @@ static void make_link(tommy_hashdyn* poolset, const char* pool_dir, const char*
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
} else if (errno == EPERM) {
|
} else if (errno == EPERM) {
|
||||||
/* LCOV_EXCL_START */
|
/* 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);
|
exit(EXIT_FAILURE);
|
||||||
/* LCOV_EXCL_STOP */
|
/* LCOV_EXCL_STOP */
|
||||||
#endif
|
#endif
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#define __USE_MINGW_ANSI_STDIO 1
|
#define __USE_MINGW_ANSI_STDIO 1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the MSVCRT version targetting Windows Vista.
|
* Define the MSVCRT version targeting Windows Vista.
|
||||||
*/
|
*/
|
||||||
#define __MSVCRT_VERSION__ 0x0600
|
#define __MSVCRT_VERSION__ 0x0600
|
||||||
|
|
||||||
@ -198,9 +198,11 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MAJOR_IN_MKDEV
|
#if HAVE_SYS_MKDEV
|
||||||
#include <sys/mkdev.h>
|
#include <sys/mkdev.h>
|
||||||
#elif MAJOR_IN_SYSMACROS
|
#endif
|
||||||
|
|
||||||
|
#if HAVE_SYS_SYSMACROS_H
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -387,14 +389,14 @@ void os_clear(void);
|
|||||||
*
|
*
|
||||||
* If no log file is selected, it's 0.
|
* If no log file is selected, it's 0.
|
||||||
*/
|
*/
|
||||||
FILE* stdlog;
|
extern FILE* stdlog;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exit codes for testing.
|
* Exit codes for testing.
|
||||||
*/
|
*/
|
||||||
int exit_success;
|
extern int exit_success;
|
||||||
int exit_failure;
|
extern int exit_failure;
|
||||||
int exit_sync_needed;
|
extern int exit_sync_needed;
|
||||||
#undef EXIT_SUCCESS
|
#undef EXIT_SUCCESS
|
||||||
#undef EXIT_FAILURE
|
#undef EXIT_FAILURE
|
||||||
#define EXIT_SUCCESS exit_success
|
#define EXIT_SUCCESS exit_success
|
||||||
|
@ -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
|
* because the metadata in the directory is updated only when the file
|
||||||
* is closed.
|
* 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.
|
* The link metadata is updated only when the link is opened.
|
||||||
* This extends also to st_size and st_nlink.
|
* This extends also to st_size and st_nlink.
|
||||||
*
|
*
|
||||||
|
@ -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");
|
log_fatal("DANGER! Unexpected data errors! The failing blocks are now marked as bad!\n");
|
||||||
if (io_error || silent_error) {
|
if (io_error || silent_error) {
|
||||||
log_fatal("Use 'snapraid status' to list the bad blocks.\n");
|
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);
|
log_tag("summary:error_file:%u\n", error);
|
||||||
|
@ -632,7 +632,7 @@ void selftest(void)
|
|||||||
}
|
}
|
||||||
if (raid_test_par(RAID_MODE_CAUCHY, 1, 256) != 0) {
|
if (raid_test_par(RAID_MODE_CAUCHY, 1, 256) != 0) {
|
||||||
/* LCOV_EXCL_START */
|
/* 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);
|
exit(EXIT_FAILURE);
|
||||||
/* LCOV_EXCL_STOP */
|
/* LCOV_EXCL_STOP */
|
||||||
}
|
}
|
||||||
|
@ -1001,6 +1001,10 @@ int main(int argc, char* argv[])
|
|||||||
switch (operation) {
|
switch (operation) {
|
||||||
case OPERATION_FIX :
|
case OPERATION_FIX :
|
||||||
case OPERATION_CHECK :
|
case OPERATION_CHECK :
|
||||||
|
case OPERATION_SMART :
|
||||||
|
case OPERATION_DEVICES :
|
||||||
|
case OPERATION_SPINUP :
|
||||||
|
case OPERATION_SPINDOWN :
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
if (opt.force_device) {
|
if (opt.force_device) {
|
||||||
|
@ -216,6 +216,7 @@ void speed(int period)
|
|||||||
printf("%8s", "best");
|
printf("%8s", "best");
|
||||||
printf("%8s", "murmur3");
|
printf("%8s", "murmur3");
|
||||||
printf("%8s", "spooky2");
|
printf("%8s", "spooky2");
|
||||||
|
printf("%8s", "metro");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
printf("%8s", "hash");
|
printf("%8s", "hash");
|
||||||
@ -245,6 +246,14 @@ void speed(int period)
|
|||||||
memhash(HASH_SPOOKY2, seed, digest, v[j], size);
|
memhash(HASH_SPOOKY2, seed, digest, v[j], size);
|
||||||
} SPEED_STOP
|
} 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("%8" PRIu64, ds / dt);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
@ -279,7 +279,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
|
|||||||
struct snapraid_disk* other = j->data;
|
struct snapraid_disk* other = j->data;
|
||||||
if (disk->device == other->device) {
|
if (disk->device == other->device) {
|
||||||
if (state->opt.force_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 */
|
/* and we DON'T mark the disk to be skipped */
|
||||||
/* because we want to use these disks */
|
/* because we want to use these disks */
|
||||||
if (!state->opt.no_warnings)
|
if (!state->opt.no_warnings)
|
||||||
@ -310,6 +310,13 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
|
|||||||
for (l = 0; l < state->level; ++l) {
|
for (l = 0; l < state->level; ++l) {
|
||||||
for (s = 0; s < state->parity[l].split_mac; ++s) {
|
for (s = 0; s < state->parity[l].split_mac; ++s) {
|
||||||
if (disk->device == state->parity[l].split_map[s].device) {
|
if (disk->device == state->parity[l].split_map[s].device) {
|
||||||
|
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 */
|
/* 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);
|
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
|
#ifdef _WIN32
|
||||||
@ -323,6 +330,7 @@ static void state_config_check(struct snapraid_state* state, const char* path, t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (state->pool[0] != 0 && disk->device == state->pool_device) {
|
if (state->pool[0] != 0 && disk->device == state->pool_device) {
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
@ -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) {
|
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->parity[l].split_map[s].device == state->parity[j].split_map[t].device) {
|
||||||
if (state->opt.force_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 */
|
/* and we DON'T mark the disk to be skipped */
|
||||||
/* because we want to use these disks */
|
/* because we want to use these disks */
|
||||||
if (!state->opt.no_warnings)
|
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;
|
state->block_size *= KIBI;
|
||||||
} else if (strcmp(tag, "hashsize") == 0
|
} 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;
|
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.
|
* 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)
|
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) {
|
if (state->block_size == 0) {
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
decoding_error(path, f);
|
decoding_error(path, f);
|
||||||
log_fatal("Internal incosistency due zero blocksize!\n");
|
log_fatal("Internal inconsistency due zero blocksize!\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
/* LCOV_EXCL_STOP */
|
/* LCOV_EXCL_STOP */
|
||||||
}
|
}
|
||||||
@ -2398,6 +2406,9 @@ static void state_read_content(struct snapraid_state* state, const char* path, S
|
|||||||
case 'k' :
|
case 'k' :
|
||||||
state->hash = HASH_SPOOKY2;
|
state->hash = HASH_SPOOKY2;
|
||||||
break;
|
break;
|
||||||
|
case 'm' :
|
||||||
|
state->hash = HASH_METRO;
|
||||||
|
break;
|
||||||
default :
|
default :
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
decoding_error(path, f);
|
decoding_error(path, f);
|
||||||
@ -2425,6 +2436,9 @@ static void state_read_content(struct snapraid_state* state, const char* path, S
|
|||||||
case 'k' :
|
case 'k' :
|
||||||
state->prevhash = HASH_SPOOKY2;
|
state->prevhash = HASH_SPOOKY2;
|
||||||
break;
|
break;
|
||||||
|
case 'm' :
|
||||||
|
state->prevhash = HASH_METRO;
|
||||||
|
break;
|
||||||
default :
|
default :
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
decoding_error(path, f);
|
decoding_error(path, f);
|
||||||
@ -2947,6 +2961,8 @@ static void* state_write_thread(void* arg)
|
|||||||
sputc('u', f);
|
sputc('u', f);
|
||||||
} else if (state->hash == HASH_SPOOKY2) {
|
} else if (state->hash == HASH_SPOOKY2) {
|
||||||
sputc('k', f);
|
sputc('k', f);
|
||||||
|
} else if (state->hash == HASH_METRO) {
|
||||||
|
sputc('m', f);
|
||||||
} else {
|
} else {
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
log_fatal("Unexpected hash when writing the content file '%s'.\n", serrorfile(f));
|
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);
|
sputc('u', f);
|
||||||
} else if (state->prevhash == HASH_SPOOKY2) {
|
} else if (state->prevhash == HASH_SPOOKY2) {
|
||||||
sputc('k', f);
|
sputc('k', f);
|
||||||
|
} else if (state->prevhash == HASH_METRO) {
|
||||||
|
sputc('m', f);
|
||||||
} else {
|
} else {
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
log_fatal("Unexpected prevhash when writing the content file '%s'.\n", serrorfile(f));
|
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)
|
static void* state_verify_thread(void* arg)
|
||||||
{
|
{
|
||||||
struct state_verify_thread_context* context = arg;
|
struct state_verify_thread_context* context = arg;
|
||||||
|
struct snapraid_content* content = context->content;
|
||||||
STREAM* f = context->f;
|
STREAM* f = context->f;
|
||||||
unsigned char buf[4];
|
unsigned char buf[4];
|
||||||
uint32_t crc_stored;
|
uint32_t crc_stored;
|
||||||
uint32_t crc_computed;
|
uint32_t crc_computed;
|
||||||
|
uint64_t start;
|
||||||
|
|
||||||
|
start = tick_ms();
|
||||||
|
|
||||||
if (sdeplete(f, buf) != 0) {
|
if (sdeplete(f, buf) != 0) {
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
@ -3872,6 +3894,8 @@ static void* state_verify_thread(void* arg)
|
|||||||
/* LCOV_EXCL_STOP */
|
/* LCOV_EXCL_STOP */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msg_progress("Verified %s in %" PRIu64 " seconds\n", content->content, (tick_ms() - start) / 1000);
|
||||||
|
|
||||||
return 0;
|
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)) {
|
if (!tommy_list_empty(filterlist_disk)) {
|
||||||
/* for each parity disk */
|
/* for each parity disk */
|
||||||
for (l = 0; l < state->level; ++l) {
|
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;
|
time_t elapsed;
|
||||||
unsigned out_perc = 0;
|
unsigned out_perc = 0;
|
||||||
unsigned out_speed = 0;
|
unsigned out_size_speed = 0;
|
||||||
|
unsigned out_block_speed = 0;
|
||||||
unsigned out_cpu = 0;
|
unsigned out_cpu = 0;
|
||||||
unsigned out_eta = 0;
|
unsigned out_eta = 0;
|
||||||
int out_computed = 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 */
|
/* estimate the speed in MB/s */
|
||||||
if (delta_time != 0)
|
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 */
|
/* estimate the cpu usage percentage */
|
||||||
if (delta_tick_total != 0)
|
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) {
|
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();
|
log_flush();
|
||||||
} else {
|
} else {
|
||||||
msg_bar("%u%%, %u MB", out_perc, (unsigned)(countsize / MEGA));
|
msg_bar("%u%%, %u MB", out_perc, (unsigned)(countsize / MEGA));
|
||||||
if (out_computed) {
|
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(", CPU %u%%", out_cpu);
|
||||||
msg_bar(", %u:%02u ETA", out_eta / 60, out_eta % 60);
|
msg_bar(", %u:%02u ETA", out_eta / 60, out_eta % 60);
|
||||||
}
|
}
|
||||||
|
@ -261,7 +261,7 @@ void state_rehash(struct snapraid_state* state);
|
|||||||
*/
|
*/
|
||||||
#define SCRUB_AUTO -1 /**< Automatic selection. */
|
#define SCRUB_AUTO -1 /**< Automatic selection. */
|
||||||
#define SCRUB_BAD -2 /**< Scrub only the bad blocks. */
|
#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_FULL -4 /**< Scrub everything. */
|
||||||
#define SCRUB_EVEN -5 /**< Even blocks. */
|
#define SCRUB_EVEN -5 /**< Even blocks. */
|
||||||
|
|
||||||
|
@ -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);
|
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);
|
f = open(file, O_WRONLY | O_CREAT | O_EXCL | O_BINARY | O_SEQUENTIAL, 0600);
|
||||||
if (f == -1) {
|
if (f == -1) {
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
@ -363,7 +363,7 @@ int sgettok(STREAM* f, char* str, int size)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (c == '\n') {
|
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')
|
if (i != str && i[-1] == '\r')
|
||||||
--i;
|
--i;
|
||||||
sungetc(c, f);
|
sungetc(c, f);
|
||||||
@ -429,7 +429,7 @@ int sgetline(STREAM* f, char* str, int size)
|
|||||||
while (1) {
|
while (1) {
|
||||||
c = *pos++;
|
c = *pos++;
|
||||||
if (c == '\n') {
|
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')
|
if (i != str && i[-1] == '\r')
|
||||||
--i;
|
--i;
|
||||||
--pos;
|
--pos;
|
||||||
@ -455,7 +455,7 @@ int sgetline(STREAM* f, char* str, int size)
|
|||||||
/* LCOV_EXCL_STOP */
|
/* LCOV_EXCL_STOP */
|
||||||
}
|
}
|
||||||
if (c == '\n') {
|
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')
|
if (i != str && i[-1] == '\r')
|
||||||
--i;
|
--i;
|
||||||
sungetc(c, f);
|
sungetc(c, f);
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
*
|
*
|
||||||
* It's not a constant for testing purpose.
|
* 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_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. */
|
#define STREAM_STATE_WRITE 1 /**< The stream is in a normal state of write. */
|
||||||
|
@ -79,6 +79,7 @@ void lock_done(void)
|
|||||||
/* print */
|
/* print */
|
||||||
|
|
||||||
int msg_level = 0;
|
int msg_level = 0;
|
||||||
|
FILE* stdlog = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that in the following functions we always flush both
|
* Note that in the following functions we always flush both
|
||||||
@ -811,7 +812,7 @@ int mkancestor(const char* file)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#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) {
|
if (isalpha(dir[0]) && dir[1] == ':' && dir[2] == 0) {
|
||||||
/* nothing more to do */
|
/* nothing more to do */
|
||||||
return 0;
|
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
|
* 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
|
* callback/continuation scheme). My worry is just doing this if a user
|
||||||
* application does something crazy, like request gigabytes and gigabytes
|
* 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
|
* way of cancelling the readahead request. Today, the user can just
|
||||||
* kill the application. But if we simply shove the work to a kernel
|
* 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
|
* 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.
|
* Implementation note about conditional variables.
|
||||||
*
|
*
|
||||||
* The conditional variables can be signaled inside or 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 ouside the mutex,
|
* what is better it's debatable but in general doing that outside the mutex,
|
||||||
* reduces the number of context switches.
|
* 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 see the dependency between the signal and the wait.
|
||||||
*
|
*
|
||||||
* To avoid it we signal everything inside the mutex. And we do this in both
|
* 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),
|
* test mode (with CHECKER defined) and release mode (CHECKER not defined),
|
||||||
* to be on the safe side and avoid any difference in beaviour between test and
|
* to be on the safe side and avoid any difference in behaviour between test and
|
||||||
* release.
|
* release.
|
||||||
*
|
*
|
||||||
* Here some interesting discussion:
|
* Here some interesting discussion:
|
||||||
|
@ -109,7 +109,7 @@ void log_flush(void);
|
|||||||
/**
|
/**
|
||||||
* Pointer to log function.
|
* Pointer to log function.
|
||||||
*/
|
*/
|
||||||
typedef void fptr(const char* format, ...);
|
typedef void fptr(const char* format, ...) __attribute__((format(attribute_printf, 1, 2)));
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
/* message */
|
/* message */
|
||||||
@ -415,7 +415,7 @@ int smartctl_flush(FILE* f, const char* file, const char* name);
|
|||||||
*
|
*
|
||||||
* Ensure to change that before starting any thread.
|
* 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.
|
* Thread wrappers to handle error conditions.
|
||||||
|
@ -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 */
|
/* 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 */
|
/* compute the new parity */
|
||||||
if (!error_on_this_block && !io_error_on_this_block && silent_error_on_this_block) {
|
if (!error_on_this_block && !io_error_on_this_block && silent_error_on_this_block) {
|
||||||
unsigned failed_mac;
|
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;
|
data_off_t out_size;
|
||||||
parity_size(&parity_handle[l], &out_size);
|
parity_size(&parity_handle[l], &out_size);
|
||||||
parity_overflow(state, 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);
|
exit(EXIT_FAILURE);
|
||||||
/* LCOV_EXCL_STOP */
|
/* LCOV_EXCL_STOP */
|
||||||
}
|
}
|
||||||
|
@ -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 */
|
/* In this way we keep them in the directory traversal order */
|
||||||
/* that at least keeps files in the same directory together. */
|
/* that at least keeps files in the same directory together. */
|
||||||
/* Note also that in newer file-system with snapshot, like ZFS, */
|
/* 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 */
|
/* are not overwritten in place, but rewritten in another location */
|
||||||
/* of the disk. */
|
/* of the disk. */
|
||||||
*physical = FILEPHY_UNREPORTED_OFFSET;
|
*physical = FILEPHY_UNREPORTED_OFFSET;
|
||||||
|
@ -59,7 +59,7 @@ int dirent_hidden(struct dirent* dd);
|
|||||||
const char* stat_desc(struct stat* st);
|
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);
|
size_t direct_size(void);
|
||||||
|
|
||||||
|
@ -470,8 +470,24 @@ static inline uint64_t util_rotl64(uint64_t x, int8_t r)
|
|||||||
return (x << r) | (x >> (64 - 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.
|
* They are needed only if BigEndian.
|
||||||
*/
|
*/
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
@ -502,6 +518,18 @@ static inline uint64_t util_swap64(uint64_t v)
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
static inline uint32_t util_read32(const void* ptr)
|
||||||
{
|
{
|
||||||
uint32_t v;
|
uint32_t v;
|
||||||
@ -543,6 +571,7 @@ static inline void util_write64(void* ptr, uint64_t v)
|
|||||||
|
|
||||||
#include "murmur3.c"
|
#include "murmur3.c"
|
||||||
#include "spooky2.c"
|
#include "spooky2.c"
|
||||||
|
#include "metro.c"
|
||||||
|
|
||||||
void memhash(unsigned kind, const unsigned char* seed, void* digest, const void* src, size_t size)
|
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 :
|
case HASH_SPOOKY2 :
|
||||||
SpookyHash128(src, size, seed, digest);
|
SpookyHash128(src, size, seed, digest);
|
||||||
break;
|
break;
|
||||||
|
case HASH_METRO :
|
||||||
|
MetroHash128(src, size, seed, digest);
|
||||||
|
break;
|
||||||
default :
|
default :
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
log_fatal("Internal inconsistency in hash function %u\n", kind);
|
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_UNDEFINED : return "undefined";
|
||||||
case HASH_MURMUR3 : return "murmur3";
|
case HASH_MURMUR3 : return "murmur3";
|
||||||
case HASH_SPOOKY2 : return "spooky2";
|
case HASH_SPOOKY2 : return "spooky2";
|
||||||
|
case HASH_METRO : return "metro";
|
||||||
default :
|
default :
|
||||||
/* LCOV_EXCL_START */
|
/* LCOV_EXCL_START */
|
||||||
return "unknown";
|
return "unknown";
|
||||||
|
@ -161,7 +161,7 @@ static inline uint32_t crc32c_plain(uint32_t crc, const unsigned char* ptr, unsi
|
|||||||
/**
|
/**
|
||||||
* Compute the CRC-32 (Castagnoli)
|
* 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.
|
* Internal entry points for testing.
|
||||||
@ -188,6 +188,7 @@ void crc32c_init(void);
|
|||||||
#define HASH_UNDEFINED 0
|
#define HASH_UNDEFINED 0
|
||||||
#define HASH_MURMUR3 1
|
#define HASH_MURMUR3 1
|
||||||
#define HASH_SPOOKY2 2
|
#define HASH_SPOOKY2 2
|
||||||
|
#define HASH_METRO 3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute the HASH of a memory block.
|
* Compute the HASH of a memory block.
|
||||||
|
14
config.h.in
14
config.h.in
@ -224,6 +224,9 @@
|
|||||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||||
#undef HAVE_SYS_IOCTL_H
|
#undef HAVE_SYS_IOCTL_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/mkdev.h> header file. */
|
||||||
|
#undef HAVE_SYS_MKDEV_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/mount.h> header file. */
|
/* Define to 1 if you have the <sys/mount.h> header file. */
|
||||||
#undef HAVE_SYS_MOUNT_H
|
#undef HAVE_SYS_MOUNT_H
|
||||||
|
|
||||||
@ -240,6 +243,9 @@
|
|||||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||||
#undef HAVE_SYS_STAT_H
|
#undef HAVE_SYS_STAT_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/sysmacros.h> header file. */
|
||||||
|
#undef HAVE_SYS_SYSMACROS_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
#undef HAVE_SYS_TYPES_H
|
#undef HAVE_SYS_TYPES_H
|
||||||
|
|
||||||
@ -258,14 +264,6 @@
|
|||||||
/* Define to 1 if you have the `vsnprintf' function. */
|
/* Define to 1 if you have the `vsnprintf' function. */
|
||||||
#undef HAVE_VSNPRINTF
|
#undef HAVE_VSNPRINTF
|
||||||
|
|
||||||
/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
|
|
||||||
*/
|
|
||||||
#undef MAJOR_IN_MKDEV
|
|
||||||
|
|
||||||
/* Define to 1 if `major', `minor', and `makedev' are declared in
|
|
||||||
<sysmacros.h>. */
|
|
||||||
#undef MAJOR_IN_SYSMACROS
|
|
||||||
|
|
||||||
/* Define to 1 if assertions should be disabled. */
|
/* Define to 1 if assertions should be disabled. */
|
||||||
#undef NDEBUG
|
#undef NDEBUG
|
||||||
|
|
||||||
|
88
configure
vendored
88
configure
vendored
@ -1,6 +1,6 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Guess values for system-dependent variables and create Makefiles.
|
# 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.
|
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
|
||||||
@ -577,8 +577,8 @@ MAKEFLAGS=
|
|||||||
# Identity of this package.
|
# Identity of this package.
|
||||||
PACKAGE_NAME='snapraid'
|
PACKAGE_NAME='snapraid'
|
||||||
PACKAGE_TARNAME='snapraid'
|
PACKAGE_TARNAME='snapraid'
|
||||||
PACKAGE_VERSION='11.3'
|
PACKAGE_VERSION='11.5'
|
||||||
PACKAGE_STRING='snapraid 11.3'
|
PACKAGE_STRING='snapraid 11.5'
|
||||||
PACKAGE_BUGREPORT=''
|
PACKAGE_BUGREPORT=''
|
||||||
PACKAGE_URL='http://www.snapraid.it'
|
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.
|
# 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.
|
# This message is too long to be a string in the A/UX 3.1 sh.
|
||||||
cat <<_ACEOF
|
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]...
|
Usage: $0 [OPTION]... [VAR=VALUE]...
|
||||||
|
|
||||||
@ -1374,7 +1374,7 @@ fi
|
|||||||
|
|
||||||
if test -n "$ac_init_help"; then
|
if test -n "$ac_init_help"; then
|
||||||
case $ac_init_help in
|
case $ac_init_help in
|
||||||
short | recursive ) echo "Configuration of snapraid 11.3:";;
|
short | recursive ) echo "Configuration of snapraid 11.5:";;
|
||||||
esac
|
esac
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
|
|
||||||
@ -1496,7 +1496,7 @@ fi
|
|||||||
test -n "$ac_init_help" && exit $ac_status
|
test -n "$ac_init_help" && exit $ac_status
|
||||||
if $ac_init_version; then
|
if $ac_init_version; then
|
||||||
cat <<\_ACEOF
|
cat <<\_ACEOF
|
||||||
snapraid configure 11.3
|
snapraid configure 11.5
|
||||||
generated by GNU Autoconf 2.69
|
generated by GNU Autoconf 2.69
|
||||||
|
|
||||||
Copyright (C) 2012 Free Software Foundation, Inc.
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
||||||
@ -2102,7 +2102,7 @@ cat >config.log <<_ACEOF
|
|||||||
This file contains any messages produced by compilers while
|
This file contains any messages produced by compilers while
|
||||||
running configure, to aid debugging if configure makes a mistake.
|
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
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
$ $0 $@
|
$ $0 $@
|
||||||
@ -2965,7 +2965,7 @@ fi
|
|||||||
|
|
||||||
# Define the identity of the package.
|
# Define the identity of the package.
|
||||||
PACKAGE='snapraid'
|
PACKAGE='snapraid'
|
||||||
VERSION='11.3'
|
VERSION='11.5'
|
||||||
|
|
||||||
|
|
||||||
cat >>confdefs.h <<_ACEOF
|
cat >>confdefs.h <<_ACEOF
|
||||||
@ -4657,6 +4657,22 @@ $as_echo "no" >&6; }
|
|||||||
fi
|
fi
|
||||||
rm -f conftest*
|
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.
|
# Check whether --enable-largefile was given.
|
||||||
if test "${enable_largefile+set}" = set; then :
|
if test "${enable_largefile+set}" = set; then :
|
||||||
@ -5115,56 +5131,6 @@ $as_echo "#define HAVE_SYS_WAIT_H 1" >>confdefs.h
|
|||||||
|
|
||||||
fi
|
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 <sys/types.h>
|
|
||||||
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
|
for ac_header in fcntl.h stddef.h stdint.h stdlib.h string.h limits.h
|
||||||
do :
|
do :
|
||||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
||||||
@ -5204,7 +5170,7 @@ fi
|
|||||||
|
|
||||||
done
|
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 :
|
do :
|
||||||
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
|
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"
|
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
|
# report actual input values of CONFIG_FILES etc. instead of their
|
||||||
# values after options handling.
|
# values after options handling.
|
||||||
ac_log="
|
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
|
generated by GNU Autoconf 2.69. Invocation command line was
|
||||||
|
|
||||||
CONFIG_FILES = $CONFIG_FILES
|
CONFIG_FILES = $CONFIG_FILES
|
||||||
@ -7436,7 +7402,7 @@ _ACEOF
|
|||||||
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
|
||||||
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
|
||||||
ac_cs_version="\\
|
ac_cs_version="\\
|
||||||
snapraid config.status 11.3
|
snapraid config.status 11.5
|
||||||
configured by $0, generated by GNU Autoconf 2.69,
|
configured by $0, generated by GNU Autoconf 2.69,
|
||||||
with options \\"\$ac_cs_config\\"
|
with options \\"\$ac_cs_config\\"
|
||||||
|
|
||||||
|
@ -17,11 +17,13 @@ AC_CHECK_PROG([SDE],[sde],[sde],[])
|
|||||||
AC_CHECK_PROG([ADVD2],[advd2],[advd2],[])
|
AC_CHECK_PROG([ADVD2],[advd2],[advd2],[])
|
||||||
AM_CONDITIONAL(HAVE_ADVD2, [test x"$ADVD2" != x])
|
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-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-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([-fno-inline-small-functions], CFLAGS="$CFLAGS -fno-inline-small-functions", [])
|
||||||
AC_CHECK_CC_OPT([-rdynamic], CFLAGS="$CFLAGS -rdynamic", [])
|
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.
|
dnl Checks for system.
|
||||||
AC_SYS_LARGEFILE
|
AC_SYS_LARGEFILE
|
||||||
@ -31,11 +33,10 @@ AC_HEADER_ASSERT
|
|||||||
AC_HEADER_DIRENT
|
AC_HEADER_DIRENT
|
||||||
AC_HEADER_TIME
|
AC_HEADER_TIME
|
||||||
AC_HEADER_SYS_WAIT
|
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([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([unistd.h getopt.h fnmatch.h io.h inttypes.h byteswap.h])
|
||||||
AC_CHECK_HEADERS([pthread.h math.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])
|
AC_CHECK_HEADERS([linux/fiemap.h linux/fs.h mach/mach_time.h execinfo.h])
|
||||||
|
|
||||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
* @ip[] Vector of @nv indexes of the valid parity blocks.
|
* @ip[] Vector of @nv indexes of the valid parity blocks.
|
||||||
* The indexes start from 0. They must be in order.
|
* The indexes start from 0. They must be in order.
|
||||||
* @nd Number of data blocks.
|
* @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.
|
* @v Vector of pointers to the blocks of data and parity.
|
||||||
* It has (@nd + @ip[@nv - 1] + 1) elements. The starting elements are the
|
* It has (@nd + @ip[@nv - 1] + 1) elements. The starting elements are the
|
||||||
* blocks for data, following with the parity blocks.
|
* blocks for data, following with the parity blocks.
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
*
|
*
|
||||||
* @n Number of integers currently in the vector.
|
* @n Number of integers currently in the vector.
|
||||||
* @v Vector of integers already sorted.
|
* @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.
|
* @i Value to insert.
|
||||||
*/
|
*/
|
||||||
void raid_insert(int n, int *v, int i);
|
void raid_insert(int n, int *v, int i);
|
||||||
|
@ -174,7 +174,7 @@ void raid_recX_avx2(int nr, int *id, int *ip, int nd, size_t size, void **vv);
|
|||||||
/*
|
/*
|
||||||
* Internal naming.
|
* 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_gen1_tag(void);
|
||||||
const char *raid_gen2_tag(void);
|
const char *raid_gen2_tag(void);
|
||||||
@ -263,7 +263,7 @@ static __always_inline void raid_avx_end(void)
|
|||||||
raid_sse_end();
|
raid_sse_end();
|
||||||
|
|
||||||
/* reset the upper part of the ymm registers */
|
/* 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 */
|
/* xmm register use */
|
||||||
asm volatile ("vzeroupper" : : : "memory");
|
asm volatile ("vzeroupper" : : : "memory");
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
* gen2 6814 [MB/s]
|
* gen2 6814 [MB/s]
|
||||||
* genz 3033 [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:
|
* in the order of 20% or more:
|
||||||
*
|
*
|
||||||
* sse2
|
* sse2
|
||||||
|
16
raid/raid.c
16
raid/raid.c
@ -63,11 +63,11 @@
|
|||||||
* computation of triple parity using power coefficients.
|
* computation of triple parity using power coefficients.
|
||||||
*
|
*
|
||||||
* Another important property of the Cauchy matrix is that we can setup
|
* 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
|
* the first two rows with coefficients equal at the RAID5 and RAID6 approach
|
||||||
* decribed, resulting in a compatible extension, and requiring SSSE3
|
* described, resulting in a compatible extension, and requiring SSSE3
|
||||||
* or AVX2 instructions only if triple parity or beyond is used.
|
* 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
|
* to make the first column of all 1, to optimize the computation for
|
||||||
* the first disk.
|
* the first disk.
|
||||||
*
|
*
|
||||||
@ -147,7 +147,7 @@
|
|||||||
* "raid/test/speedtest.c" program.
|
* "raid/test/speedtest.c" program.
|
||||||
*
|
*
|
||||||
* For comparison, the triple parity computation using the power
|
* 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.
|
* the Cauchy matrix if SSSE3 or AVX2 is present.
|
||||||
*
|
*
|
||||||
* int8 int32 int64 sse2 ssse3 avx2
|
* 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
|
* All these functions give the guarantee that parities are written
|
||||||
* in order. First parity P, then parity Q, and so on.
|
* in order. First parity P, then parity Q, and so on.
|
||||||
* This allows to specify the same memory buffer for multiple parities
|
* 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
|
* This characteristic is used by the raid_delta_gen() function to
|
||||||
* avoid to damage unused parities in recovering.
|
* avoid to damage unused parities in recovering.
|
||||||
*
|
*
|
||||||
* @nd Number of data blocks
|
* @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.
|
* @v Vector of pointers to the blocks of data and parity.
|
||||||
* It has (@nd + #parities) elements. The starting elements are the blocks
|
* It has (@nd + #parities) elements. The starting elements are the blocks
|
||||||
* for data, following with the parity 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 {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Unused parities are going to be rewritten with
|
* 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
|
* functions able to compute only a subset of
|
||||||
* parities.
|
* 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.
|
* The indexes start from 0. They must be in order.
|
||||||
* @nd Number of data blocks.
|
* @nd Number of data blocks.
|
||||||
* @np Number of parity 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.
|
* @v Vector of pointers to the blocks of data and parity.
|
||||||
* It has (@nd + @np) elements. The starting elements are the blocks
|
* It has (@nd + @np) elements. The starting elements are the blocks
|
||||||
* for data, following with the parity blocks.
|
* for data, following with the parity blocks.
|
||||||
|
@ -13662,8 +13662,8 @@ const uint8_t __aligned(256) raid_gfcauchypshufb[251][4][2][16] =
|
|||||||
/**
|
/**
|
||||||
* PSHUFB tables for generic multiplication.
|
* PSHUFB tables for generic multiplication.
|
||||||
*
|
*
|
||||||
* Indexes are [MULTIPLER][LH].
|
* Indexes are [MULTIPLIER][LH].
|
||||||
* Where MULTIPLER is from 0 to 255, LH from 0 to 1.
|
* Where MULTIPLIER is from 0 to 255, LH from 0 to 1.
|
||||||
*/
|
*/
|
||||||
const uint8_t __aligned(256) raid_gfmulpshufb[256][2][16] =
|
const uint8_t __aligned(256) raid_gfmulpshufb[256][2][16] =
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#
|
#
|
||||||
# selftest - Runs the same selftest and speedtest executed at the module startup.
|
# 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.
|
# 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
|
# invtest - Runs an extensive matrix inversion test of all the 377.342.351.231
|
||||||
# possible square submatrices of the Cauchy matrix used.
|
# possible square submatrices of the Cauchy matrix used.
|
||||||
# covtest - Runs a coverage test.
|
# covtest - Runs a coverage test.
|
||||||
|
11
snapraid.1
11
snapraid.1
@ -79,6 +79,9 @@ Beside the ability to recover from disk failures, other
|
|||||||
features of SnapRAID are:
|
features of SnapRAID are:
|
||||||
.PD 0
|
.PD 0
|
||||||
.IP \(bu
|
.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
|
All your data is hashed to ensure data integrity and to avoid
|
||||||
silent corruption.
|
silent corruption.
|
||||||
.IP \(bu
|
.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
|
If you accidentally delete some files in a disk, you can
|
||||||
recover them.
|
recover them.
|
||||||
.IP \(bu
|
.IP \(bu
|
||||||
You can start with already filled disks.
|
|
||||||
.IP \(bu
|
|
||||||
The disks can have different sizes.
|
The disks can have different sizes.
|
||||||
.IP \(bu
|
.IP \(bu
|
||||||
You can add disks at any time.
|
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
|
It doesn\'t lock\-in your data. You can stop using SnapRAID at any
|
||||||
time without the need to reformat or move data.
|
time without the need to reformat or move data.
|
||||||
.IP \(bu
|
.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.
|
producing less noise.
|
||||||
.PD
|
.PD
|
||||||
.PP
|
.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.
|
If bad blocks were detected, their block numbers are listed.
|
||||||
To fix them, you can use the \[dq]fix \-e\[dq] command.
|
To fix them, you can use the \[dq]fix \-e\[dq] command.
|
||||||
.PP
|
.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 \'*\',
|
was scrubbed or synced. Scrubbed blocks are shown with \'*\',
|
||||||
blocks synced but not yet scrubbed with \'o\'.
|
blocks synced but not yet scrubbed with \'o\'.
|
||||||
.PP
|
.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],
|
To only fix the blocks marked bad during \[dq]sync\[dq] and \[dq]scrub\[dq],
|
||||||
use the \-e, \-\-filter\-error option.
|
use the \-e, \-\-filter\-error option.
|
||||||
As difference from other filter options, with this one the fixes are
|
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
|
.PP
|
||||||
All the files that cannot be fixed are renamed adding the
|
All the files that cannot be fixed are renamed adding the
|
||||||
\[dq].unrecoverable\[dq] extension.
|
\[dq].unrecoverable\[dq] extension.
|
||||||
|
@ -31,6 +31,8 @@ Description
|
|||||||
Beside the ability to recover from disk failures, other
|
Beside the ability to recover from disk failures, other
|
||||||
features of SnapRAID are:
|
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
|
* All your data is hashed to ensure data integrity and to avoid
|
||||||
silent corruption.
|
silent corruption.
|
||||||
* If the failed disks are too many to allow a recovery,
|
* 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.
|
All the data in the other disks is safe.
|
||||||
* If you accidentally delete some files in a disk, you can
|
* If you accidentally delete some files in a disk, you can
|
||||||
recover them.
|
recover them.
|
||||||
* You can start with already filled disks.
|
|
||||||
* The disks can have different sizes.
|
* The disks can have different sizes.
|
||||||
* You can add disks at any time.
|
* You can add disks at any time.
|
||||||
* It doesn't lock-in your data. You can stop using SnapRAID at any
|
* It doesn't lock-in your data. You can stop using SnapRAID at any
|
||||||
time without the need to reformat or move data.
|
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.
|
producing less noise.
|
||||||
|
|
||||||
The official site of SnapRAID is:
|
The official site of SnapRAID is:
|
||||||
@ -400,7 +401,7 @@ Commands
|
|||||||
If bad blocks were detected, their block numbers are listed.
|
If bad blocks were detected, their block numbers are listed.
|
||||||
To fix them, you can use the "fix -e" command.
|
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 '*',
|
was scrubbed or synced. Scrubbed blocks are shown with '*',
|
||||||
blocks synced but not yet scrubbed with 'o'.
|
blocks synced but not yet scrubbed with 'o'.
|
||||||
|
|
||||||
@ -577,7 +578,7 @@ Commands
|
|||||||
To only fix the blocks marked bad during "sync" and "scrub",
|
To only fix the blocks marked bad during "sync" and "scrub",
|
||||||
use the -e, --filter-error option.
|
use the -e, --filter-error option.
|
||||||
As difference from other filter options, with this one the fixes are
|
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
|
All the files that cannot be fixed are renamed adding the
|
||||||
".unrecoverable" extension.
|
".unrecoverable" extension.
|
||||||
|
@ -38,6 +38,8 @@ big files that rarely change.
|
|||||||
Beside the ability to recover from disk failures, other
|
Beside the ability to recover from disk failures, other
|
||||||
features of SnapRAID are:
|
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
|
* All your data is hashed to ensure data integrity and to avoid
|
||||||
silent corruption.
|
silent corruption.
|
||||||
* If the failed disks are too many to allow a recovery,
|
* 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.
|
All the data in the other disks is safe.
|
||||||
* If you accidentally delete some files in a disk, you can
|
* If you accidentally delete some files in a disk, you can
|
||||||
recover them.
|
recover them.
|
||||||
* You can start with already filled disks.
|
|
||||||
* The disks can have different sizes.
|
* The disks can have different sizes.
|
||||||
* You can add disks at any time.
|
* You can add disks at any time.
|
||||||
* It doesn't lock-in your data. You can stop using SnapRAID at any
|
* It doesn't lock-in your data. You can stop using SnapRAID at any
|
||||||
time without the need to reformat or move data.
|
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.
|
producing less noise.
|
||||||
|
|
||||||
The official site of SnapRAID is:
|
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.
|
If bad blocks were detected, their block numbers are listed.
|
||||||
To fix them, you can use the "fix -e" command.
|
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 '*',
|
was scrubbed or synced. Scrubbed blocks are shown with '*',
|
||||||
blocks synced but not yet scrubbed with 'o'.
|
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",
|
To only fix the blocks marked bad during "sync" and "scrub",
|
||||||
use the -e, --filter-error option.
|
use the -e, --filter-error option.
|
||||||
As difference from other filter options, with this one the fixes are
|
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
|
All the files that cannot be fixed are renamed adding the
|
||||||
".unrecoverable" extension.
|
".unrecoverable" extension.
|
||||||
|
@ -114,7 +114,7 @@ tommy_inline void tommy_chain_merge(tommy_chain* first, tommy_chain* second, tom
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges two chains managing special degenerated cases.
|
* 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)
|
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.
|
* Bit buckets of chains.
|
||||||
* Each bucket contains 2^i nodes or it's empty.
|
* 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.
|
* We keep it in the same "bit" vector to avoid reports from the valgrind tool sgcheck.
|
||||||
*/
|
*/
|
||||||
tommy_chain bit[TOMMY_SIZE_BIT + 1];
|
tommy_chain bit[TOMMY_SIZE_BIT + 1];
|
||||||
|
@ -231,7 +231,7 @@ tommy_uint32_t tommy_strhash_u32(tommy_uint64_t init_val, const void* void_key)
|
|||||||
key += 12;
|
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 */
|
/* this is different than the original lookup3 and the result won't match */
|
||||||
|
|
||||||
tommy_final(a, b, c);
|
tommy_final(a, b, c);
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
* \param void_key Pointer to the data to hash.
|
* \param void_key Pointer to the data to hash.
|
||||||
* \param key_len Size of the data to hash.
|
* \param key_len Size of the data to hash.
|
||||||
* \note
|
* \note
|
||||||
* This function is endianess independent.
|
* This function is endianness independent.
|
||||||
* \return The hash value of 32 bits.
|
* \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);
|
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 void_key Pointer to the data to hash.
|
||||||
* \param key_len Size of the data to hash.
|
* \param key_len Size of the data to hash.
|
||||||
* \note
|
* \note
|
||||||
* This function is endianess independent.
|
* This function is endianness independent.
|
||||||
* \return The hash value of 64 bits.
|
* \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);
|
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.
|
* 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().
|
* from http://www.burtleburtle.net/bob/hash/doobs.html, function hashlittle().
|
||||||
*
|
*
|
||||||
* This hash is designed to handle strings with an unknown length. If you
|
* 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.
|
* Use 0 if not relevant.
|
||||||
* \param void_key Pointer to the string to hash. It has to be 0 terminated.
|
* \param void_key Pointer to the string to hash. It has to be 0 terminated.
|
||||||
* \note
|
* \note
|
||||||
* This function is endianess independent.
|
* This function is endianness independent.
|
||||||
* \return The hash value of 32 bits.
|
* \return The hash value of 32 bits.
|
||||||
*/
|
*/
|
||||||
tommy_uint32_t tommy_strhash_u32(tommy_uint64_t init_val, const void* void_key);
|
tommy_uint32_t tommy_strhash_u32(tommy_uint64_t init_val, const void* void_key);
|
||||||
|
@ -92,7 +92,7 @@
|
|||||||
*
|
*
|
||||||
* To iterate over all the elements in the hashtable with the same key, you have to
|
* 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.
|
* 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.
|
* different keys.
|
||||||
*
|
*
|
||||||
* \code
|
* \code
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
/** \file
|
/** \file
|
||||||
* Double linked list for collisions into hashtables.
|
* 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.
|
* 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
|
* 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 a stable merge sort with O(N*log(N)) worst complexity.
|
||||||
* It's faster on degenerated cases like partially ordered lists.
|
* It's faster on degenerated cases like partially ordered lists.
|
||||||
* \param cmp Compare function called with two elements.
|
* \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);
|
void tommy_list_sort(tommy_list* list, tommy_compare_func* cmp);
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
*
|
*
|
||||||
* As difference than other tommy containers, duplicate elements cannot be inserted.
|
* 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.
|
* function that will define the order in the tree.
|
||||||
*
|
*
|
||||||
* \code
|
* \code
|
||||||
@ -123,7 +123,7 @@ typedef struct tommy_tree_struct {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the tree.
|
* 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);
|
void tommy_tree_init(tommy_tree* tree, tommy_compare_func* cmp);
|
||||||
|
|
||||||
|
@ -227,7 +227,7 @@ typedef struct tommy_node_struct {
|
|||||||
* Compare function for elements.
|
* Compare function for elements.
|
||||||
* \param obj_a Pointer to the first object to compare.
|
* \param obj_a Pointer to the first object to compare.
|
||||||
* \param obj_b Pointer to the second 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().
|
* This function is like the C strcmp().
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user