Adds preliminary support for spinning up and down commands.

This commit is contained in:
Andrea Mazzoleni 2015-01-02 15:53:15 +01:00
parent 6301301025
commit b24807704e
14 changed files with 640 additions and 47 deletions

View file

@ -3,6 +3,8 @@ SnapRAID HISTORY
8.0 2015/01 BETA
================
* Adds new "spinup" and "spindown" commands to control the disks of
the array. Note that "spindown" is available only in Linux.
* Allows "sync" and "scrub" to continue after the first
bunch of disk errors. Blocks with errors are marked as bad,
and you can fix them with the "fix -e" command.

View file

@ -31,6 +31,7 @@ snapraid_SOURCES = \
cmdline/parity.c \
cmdline/handle.c \
cmdline/nano.c \
cmdline/spin.c \
cmdline/fnmatch.c \
cmdline/selftest.c \
cmdline/speed.c \
@ -198,6 +199,9 @@ endif
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) status -l ">&2"
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) status -l ">>test.log"
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) status -l test-%D-%T.log
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) up
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) down
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) test-devices
if HAVE_SYMLINK
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(PAR1) pool
endif

View file

@ -1743,5 +1743,13 @@ int windows_randomize(void* ptr, size_t size)
return 0;
}
int diskspin(tommy_list* list, int operation)
{
(void)list;
(void)operation;
return -1;
}
#endif

View file

@ -162,6 +162,10 @@
#include "fnmatch.h"
#endif
#if HAVE_PTHREAD_H
#include <pthread.h>
#endif
/**
* Disable case check in Windows.
*/
@ -197,6 +201,8 @@
#include "unix.h"
#endif
#include "tommyds/tommylist.h"
/**
* Another name for link() to avoid confusion with local variables called "link".
*/
@ -253,6 +259,11 @@ int fsinfo(const char* path, int* has_persistent_inode, uint64_t* total_space, u
*/
uint64_t tick(void);
/**
* Get the tick counter value in millisecond.
*/
uint64_t tick_ms(void);
/**
* Initializes the system.
*/
@ -278,5 +289,27 @@ int exit_failure;
#define EXIT_SUCCESS exit_success
#define EXIT_FAILURE exit_failure
/**
* Disk entry.
*/
struct disk_struct {
char path[PATH_MAX]; /**< Mount point or contained directory. */
uint64_t device; /**< Device ID. */
#if HAVE_PTHREAD_CREATE
pthread_t thread;
#endif
tommy_node node;
};
typedef struct disk_struct disk_t;
#define SPIN_DOWN 0
#define SPIN_UP 1
#define SPIN_DEVICES -1
/**
* Spin all disks.
*/
int diskspin(tommy_list* list, int operation);
#endif

View file

@ -37,14 +37,17 @@ void usage(void)
{
version();
printf("Usage: " PACKAGE " diff|sync|status|scrub|dup|pool|check|fix [options]\n");
printf("Usage: " PACKAGE " status|diff|sync|scrub|list|dup|up|down|pool|check|fix [options]\n");
printf("\n");
printf("Commands:\n");
printf(" status Print the status of the array\n");
printf(" diff Show the changes that needs to be syncronized\n");
printf(" sync Syncronize the state of the array\n");
printf(" status Print the status of the array\n");
printf(" scrub Scrub the array\n");
printf(" list List the array content\n");
printf(" dup Find duplicate files\n");
printf(" up Spinup the array\n");
printf(" down Spindown the array\n");
printf(" pool Create or update the virtual view of the array\n");
printf(" check Check the array\n");
printf(" fix Fix the array\n");
@ -378,6 +381,9 @@ void signal_handler(int signal)
#define OPERATION_STATUS 10
#define OPERATION_REWRITE 11
#define OPERATION_NANO 12
#define OPERATION_SPINUP 13
#define OPERATION_SPINDOWN 14
#define OPERATION_DEVICES 15
int main(int argc, char* argv[])
{
@ -731,6 +737,12 @@ int main(int argc, char* argv[])
operation = OPERATION_REWRITE;
} else if (strcmp(argv[optind], "test-nano") == 0) {
operation = OPERATION_NANO;
} else if (strcmp(argv[optind], "up") == 0) {
operation = OPERATION_SPINUP;
} else if (strcmp(argv[optind], "down") == 0) {
operation = OPERATION_SPINDOWN;
} else if (strcmp(argv[optind], "test-devices") == 0) {
operation = OPERATION_DEVICES;
} else {
/* LCOV_EXCL_START */
fprintf(stderr, "Unknown command '%s'\n", argv[optind]);
@ -849,6 +861,7 @@ int main(int argc, char* argv[])
case OPERATION_STATUS :
case OPERATION_REWRITE :
case OPERATION_REHASH :
case OPERATION_SPINUP : /* skip because we want to do it in parallel */
/* avoid to check and access data disks if not needed */
opt.skip_disk_access = 1;
break;
@ -863,11 +876,25 @@ int main(int argc, char* argv[])
case OPERATION_REWRITE :
case OPERATION_REHASH :
case OPERATION_NANO :
case OPERATION_SPINUP : /* skip because we want to do it in parallel */
/* avoid to check and access parity disks if not needed */
opt.skip_parity_access = 1;
break;
}
switch (operation) {
case OPERATION_DIFF :
case OPERATION_LIST :
case OPERATION_DUP :
case OPERATION_POOL :
case OPERATION_NANO :
case OPERATION_SPINUP :
case OPERATION_SPINDOWN :
case OPERATION_DEVICES :
opt.skip_self = 1;
break;
}
/* open the log file */
log_open(log);
@ -1050,6 +1077,12 @@ int main(int argc, char* argv[])
state_write(&state);
memory();
} else if (operation == OPERATION_SPINUP) {
state_spin(&state, SPIN_UP);
} else if (operation == OPERATION_SPINDOWN) {
state_spin(&state, SPIN_DOWN);
} else if (operation == OPERATION_DEVICES) {
state_spin(&state, SPIN_DEVICES);
} else if (operation == OPERATION_STATUS) {
state_read(&state);

View file

@ -217,6 +217,11 @@ void state_scan(struct snapraid_state* state, int is_diff);
*/
void state_nano(struct snapraid_state* state);
/**
* Spin up/down disks.
*/
void state_spin(struct snapraid_state* state, int operation);
/**
* Syncs the parity data.
*/

View file

@ -19,6 +19,8 @@
#ifndef __MINGW32__ /* Only for Unix */
#include "util.h"
/**
* Standard exit codes.
*/
@ -300,6 +302,16 @@ uint64_t tick(void)
#endif
}
uint64_t tick_ms(void)
{
struct timeval tv;
if (gettimeofday(&tv, 0) != 0)
return 0;
return tv.tv_sec * 1000ULL + tv.tv_usec / 1000;
}
int randomize(void* ptr, size_t size)
{
int f;
@ -321,6 +333,453 @@ int randomize(void* ptr, size_t size)
return 0;
}
/**
* Read a file extracting the contained device number in %u:%u format.
* Returns 0 on error.
*/
static dev_t devread(const char* path)
{
int f;
int ret;
char buf[64];
char* e;
unsigned ma;
unsigned mi;
f = open(path, O_RDONLY);
if (f == -1) {
/* LCOV_EXCL_START */
fprintf(stderr, "Failed to open '%s'.\n", path);
return 0;
/* LCOV_EXCL_STOP */
}
ret = read(f, buf, sizeof(buf));
if (ret < 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Failed to read '%s'.\n", path);
return 0;
/* LCOV_EXCL_STOP */
}
if (ret == sizeof(buf)) {
/* LCOV_EXCL_START */
fprintf(stderr, "Too long read '%s'.\n", path);
return 0;
/* LCOV_EXCL_STOP */
}
buf[ret] = 0;
ma = strtoul(buf, &e, 10);
if (*e != ':') {
/* LCOV_EXCL_START */
fprintf(stderr, "Invalid format in '%s' for '%s'.\n", path, buf);
return 0;
/* LCOV_EXCL_STOP */
}
mi = strtoul(e+1, &e, 10);
if (*e != 0 && !isspace(*e)) {
/* LCOV_EXCL_START */
fprintf(stderr, "Invalid format in '%s' for '%s'.\n", path, buf);
return 0;
/* LCOV_EXCL_STOP */
}
ret = close(f);
if (ret != 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Failed to close '%s'.\n", path);
return 0;
/* LCOV_EXCL_STOP */
}
return makedev(ma, mi);
}
/**
* Read a device tree filling the specified list of disk_t entries.
*/
static int devtree(dev_t device, tommy_list* list)
{
char path[PATH_MAX];
DIR* d;
int slaves = 0;
pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/slaves", major(device), minor(device));
/* check if there is a slaves list */
d = opendir(path);
if (d != 0) {
struct dirent* dd;
while ((dd = readdir(d)) != 0) {
if (dd->d_name[0] != '.') {
/* for each slave, expand the full potential tree */
pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/slaves/%s/dev", major(device), minor(device), dd->d_name);
device = devread(path);
if (!device) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
if (devtree(device, list) != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
++slaves;
}
}
closedir(d);
}
/* if no slaves found */
if (!slaves) {
/* this is a raw device */
struct stat st;
disk_t* disk;
char buf[PATH_MAX];
int ret;
/* check if it's a partition */
pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/partition", major(device), minor(device));
if (stat(path, &st) == 0) {
/* get the parent device */
pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/../dev", major(device), minor(device));
device = devread(path);
if (!device) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
}
/* resolve the link from /dev/block */
pathprint(path, sizeof(path), "/dev/block/%u:%u", major(device), minor(device));
ret = readlink(path, buf, sizeof(buf));
if (ret < 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Failed to readlink '%s'.\n", path);
return 0;
/* LCOV_EXCL_STOP */
}
if (ret == sizeof(buf)) {
/* LCOV_EXCL_START */
fprintf(stderr, "Too long readlink '%s'.\n", path);
return 0;
/* LCOV_EXCL_STOP */
}
buf[ret] = 0;
if (buf[0] != '.' || buf[1] != '.' || buf[2] != '/') {
/* LCOV_EXCL_START */
fprintf(stderr, "Unexpected link '%s' at '%s'.\n", buf, path);
return 0;
/* LCOV_EXCL_STOP */
}
disk = malloc_nofail(sizeof(disk_t));
pathprint(disk->path, sizeof(disk->path), "/dev/%s", buf + 3);
disk->device = device;
/* check the device */
if (stat(path, &st) != 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Failed to stat '%s'.\n", disk->path);
return 0;
/* LCOV_EXCL_STOP */
}
if (st.st_rdev != device) {
/* LCOV_EXCL_START */
fprintf(stderr, "Unexpected device '%u:%u' instead of '%u:%u' for '%s'.\n", major(st.st_rdev), minor(st.st_rdev), major(device), minor(device), disk->path);
return 0;
/* LCOV_EXCL_STOP */
}
/* insert in the list */
tommy_list_insert_tail(list, &disk->node, disk);
}
return 0;
}
/**
* Spin down a specific device.
*/
static int devdown(dev_t device)
{
char cmd[128];
int ret;
snprintf(cmd, sizeof(cmd), "hdparm -y /dev/block/%u:%u >/dev/null 2>/dev/null", major(device), minor(device));
ret = system(cmd);
if (ret == -1) {
/* LCOV_EXCL_START */
fprintf(stderr, "Failed to run hdparm -y on device '%u:%u' (from system).\n", major(device), minor(device));
return -1;
/* LCOV_EXCL_STOP */
}
if (WEXITSTATUS(ret) == 127) {
/* LCOV_EXCL_START */
fprintf(stderr, "Failed to run hdparm -y on device '%u:%u' (from sh).\n", major(device), minor(device));
return -1;
/* LCOV_EXCL_STOP */
}
if (WEXITSTATUS(ret) != 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Failed to run hdparm -y on device '%u:%u' with return code %u.\n", major(device), minor(device), WEXITSTATUS(ret));
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
}
/**
* Compare two device entries.
*/
static int devcompare(const void* void_a, const void* void_b)
{
const disk_t* a = void_a;
const disk_t* b = void_b;
if (a->device < b->device)
return -1;
if (a->device > b->device)
return 1;
return strcmp(a->path, b->path);
}
/**
* Thread for spinning up.
*
* There isn't a defined way to spin up a device,
* so we just do a generic write access.
*/
static void* spinup(void* arg)
{
disk_t* disk = arg;
dev_t device;
int ret;
uint64_t start;
struct stat st;
start = tick_ms();
/* first get the device number, this usually doesn't trigger a spinup */
if (stat(disk->path, &st) != 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Failed to stat device '%s'.\n", disk->path);
return (void*)-1;
/* LCOV_EXCL_STOP */
}
/* set the device number for printing */
device = st.st_dev;
/* add a temporary name used for writing */
pathcat(disk->path, sizeof(disk->path), ".snapraid-spinup");
/* do a generic write, and immediately undo it */
ret = mkdir(disk->path, 0);
if (ret == 0)
rmdir(disk->path);
/* remove the added name */
pathcut(disk->path);
printf("Spunup device '%u:%u' at '%s' in %" PRIu64 " ms.\n", major(device), minor(device), disk->path, tick_ms() - start);
return 0;
}
/**
* Thread for spinning down.
*/
static void* spindown(void* arg)
{
disk_t* disk = arg;
dev_t device = disk->device;
uint64_t start;
start = tick_ms();
if (devdown(device) != 0) {
/* LCOV_EXCL_START */
return (void*)-1;
/* LCOV_EXCL_STOP */
}
printf("Spundown device '%u:%u' at '%s' in %" PRIu64 " ms.\n", major(device), minor(device), disk->path, tick_ms() - start);
return 0;
}
/**
* Lists all the devices.
*/
static int spin_devices(tommy_list* list)
{
tommy_node* i;
for (i = tommy_list_head(list); i != 0; i = i->next) {
tommy_list tree;
tommy_node* j;
disk_t* disk = i->data;
tommy_list_init(&tree);
/* expand the tree of devices */
if (devtree(disk->device, &tree) != 0) {
/* LCOV_EXCL_START */
tommy_list_foreach(&tree, free);
fprintf(stderr, "Failed to expand device '%u:%u'.\n", major(disk->device), minor(disk->device));
return -1;
/* LCOV_EXCL_STOP */
}
for (j = tommy_list_head(&tree); j != 0; j = j->next) {
disk_t* entry = j->data;
printf("%u:%u\t%s\t%u:%u\t%s\n", major(entry->device), minor(entry->device), entry->path, major(disk->device), minor(disk->device), disk->path);
}
tommy_list_foreach(&tree, free);
}
return 0;
}
int diskspin(tommy_list* list, int operation)
{
tommy_node* i;
tommy_list tree;
int fail = 0;
if (operation == SPIN_DOWN || operation == SPIN_DEVICES) {
struct stat st;
/* sysfs and devfs interfaces are required */
if (stat("/sys/dev/block", &st) != 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Missing interface sys/dev/block.\n");
return -1;
/* LCOV_EXCL_STOP */
}
if (stat("/dev/block", &st) != 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Missing interface dev/block.\n");
return -1;
/* LCOV_EXCL_STOP */
}
}
if (operation == SPIN_DEVICES)
return spin_devices(list);
tommy_list_init(&tree);
if (operation == SPIN_DOWN) {
/* for each device */
for (i = tommy_list_head(list); i != 0; i = i->next) {
disk_t* disk = i->data;
/* expand the tree of devices */
if (devtree(disk->device, &tree) != 0) {
/* LCOV_EXCL_START */
tommy_list_foreach(&tree, free);
fprintf(stderr, "Failed to expand device '%u:%u'.\n", major(disk->device), minor(disk->device));
return -1;
/* LCOV_EXCL_STOP */
}
}
} else {
/* duplicate the list */
for (i = tommy_list_head(list); i != 0; i = i->next) {
disk_t* disk = i->data;
disk_t* entry;
entry = malloc_nofail(sizeof(disk_t));
pathcpy(entry->path, sizeof(entry->path), disk->path);
entry->device = disk->device;
/* insert in the list */
tommy_list_insert_tail(&tree, &entry->node, entry);
}
}
/* sort the list */
tommy_list_sort(&tree, devcompare);
/* removes duplicates */
for (i = tommy_list_head(&tree); i != 0; i = i->next) {
while (i->next != 0 && devcompare(i->data, i->next->data) == 0)
free(tommy_list_remove_existing(&tree, i->next));
}
#if HAVE_PTHREAD_CREATE
/* starts all threads */
for (i = tommy_list_head(&tree); i != 0; i = i->next) {
disk_t* disk = i->data;
if (pthread_create(&disk->thread, 0, operation == SPIN_UP ? &spinup : &spindown, disk) != 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Failed to create thread.\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
/* joins all threads */
for (i = tommy_list_head(&tree); i != 0; i = i->next) {
disk_t* disk = i->data;
void* retval;
if (pthread_join(disk->thread, &retval) != 0) {
/* LCOV_EXCL_START */
fprintf(stderr, "Failed to join thread.\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (retval != 0)
++fail;
}
#else
for (i = tommy_list_head(&tree); i != 0; i = i->next) {
disk_t* disk = i->data;
if (operation == SPIN_UP) {
if (spinup(disk) != 0)
++fail;
} else {
if (spindown(disk) != 0)
++fail;
}
}
#endif
tommy_list_foreach(&tree, free);
if (fail != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
}
void os_init(int opt)
{
(void)opt;

View file

@ -1343,6 +1343,15 @@ void pathslash(char* dst, size_t size)
}
}
void pathcut(char* dst)
{
char* slash = strrchr(dst, '/');
if (slash)
slash[1] = 0;
else
dst[0] = 0;
}
int pathcmp(const char* a, const char* b)
{
#ifdef _WIN32

View file

@ -435,6 +435,11 @@ void pathprint(char* dst, size_t size, const char* format, ...);
*/
void pathslash(char* dst, size_t size);
/**
* Cuts everything after the latest slash.
*/
void pathcut(char* dst);
/**
* Compare two paths.
* In Windows it's case insentive and assumes \ equal at /.

View file

@ -25,6 +25,7 @@ AC_HEADER_DIRENT
AC_HEADER_TIME
AC_CHECK_HEADERS([fcntl.h stddef.h stdint.h stdlib.h string.h limits.h])
AC_CHECK_HEADERS([unistd.h getopt.h fnmatch.h io.h inttypes.h byteswap.h])
AC_CHECK_HEADERS([pthread.h])
AC_CHECK_HEADERS([sys/time.h sys/file.h sys/ioctl.h sys/vfs.h sys/statfs.h sys/param.h sys/mount.h])
AC_CHECK_HEADERS([linux/fiemap.h linux/fs.h mach/mach_time.h])
@ -80,6 +81,8 @@ AC_CHECK_FUNCS([fstatat flock statfs])
AC_CHECK_FUNCS([mach_absolute_time])
AC_SEARCH_LIBS([clock_gettime], [rt])
AC_CHECK_FUNCS([clock_gettime])
AC_CHECK_CC_OPT([-pthread], CFLAGS="$CFLAGS -pthread", [])
AC_CHECK_FUNCS([pthread_create])
dnl Checks for architecture
AC_C_BIGENDIAN
@ -167,14 +170,14 @@ AM_CONDITIONAL(HAVE_SYMLINK, [test x"$SYMLINK" != x])
AC_ARG_ENABLE([profiler],
[AS_HELP_STRING([--enable-profiler],[enable the use of gprof for code coverage])],
[
CFLAGS="-O2 -pg -g"
CFLAGS="-O2 -pg -g -pthread"
],
[])
AC_ARG_ENABLE([coverage],
[AS_HELP_STRING([--enable-coverage],[enable the use of gcov for code coverage])],
[
CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage -pthread"
],
[])
@ -216,7 +219,7 @@ AM_CONDITIONAL(HAVE_EMULATOR, [test x"$EMULATOR" != x])
AC_ARG_ENABLE([debug],
[AS_HELP_STRING([--enable-debug],[enable debugging])],
[
CFLAGS="-O0 -g -Wall -Wextra"
CFLAGS="-O0 -g -pthread -Wall -Wextra"
],
[])

View file

@ -50,7 +50,7 @@ snapraid [\-c, \-\-conf CONFIG]
.PD 0
.PP
.PD
status|sync|scrub|fix|check|list|diff|dup|pool|rehash
status|diff|sync|scrub|fix|check|list|dup|up|down|pool|rehash
.PD 0
.PP
.PD
@ -647,6 +647,14 @@ Note that the information presented refers at the latest time you run \[dq]sync\
Later modifications are not taken into account.
.PP
Nothing is modified.
.SS diff
Lists all the files modified from the last \[dq]sync\[dq] that need to have
their parity data recomputed.
.PP
This command doesn\'t check the file data, but only the file timestamp
size and inode.
.PP
Nothing is modified.
.SS sync
Updates the parity information. All the modified files
in the disk array are read, and the corresponding parity
@ -751,20 +759,20 @@ Lists all the files contained in the array at the time of the
last \[dq]sync\[dq].
.PP
Nothing is modified.
.SS diff
Lists all the files modified from the last \[dq]sync\[dq] that need to have
their parity data recomputed.
.PP
This command doesn\'t check the file data, but only the file timestamp
size and inode.
.PP
Nothing is modified.
.SS dup
Lists all the duplicate files. Two files are assumed equal if their
hashes are matching. The file data is not read, but only the
precomputed hashes are used.
.PP
Nothing is modified.
.SS up
Spins up all the disks of the array.
.PP
Nothing is modified.
.SS down
Spins down all the disks of the array.
.PP
Nothing is modified.
.SS pool
Creates or updates in the \[dq]pooling\[dq] directory a virtual view of all
the files of your disk array.

View file

@ -14,7 +14,7 @@ Synopsis
: [-S, --start BLKSTART] [-B, --count BLKCOUNT]
: [-L, --error-limit NUMBER]
: [-v, --verbose]
: status|sync|scrub|fix|check|list|diff|dup|pool|rehash
: status|diff|sync|scrub|fix|check|list|dup|up|down|pool|rehash
:snapraid [-V, --version] [-H, --help] [-C, --gen-conf CONTENT]
@ -375,6 +375,15 @@ Commands
Nothing is modified.
diff
Lists all the files modified from the last "sync" that need to have
their parity data recomputed.
This command doesn't check the file data, but only the file timestamp
size and inode.
Nothing is modified.
sync
Updates the parity information. All the modified files
in the disk array are read, and the corresponding parity
@ -484,15 +493,6 @@ Commands
Nothing is modified.
diff
Lists all the files modified from the last "sync" that need to have
their parity data recomputed.
This command doesn't check the file data, but only the file timestamp
size and inode.
Nothing is modified.
dup
Lists all the duplicate files. Two files are assumed equal if their
hashes are matching. The file data is not read, but only the
@ -500,6 +500,16 @@ Commands
Nothing is modified.
up
Spins up all the disks of the array.
Nothing is modified.
down
Spins down all the disks of the array.
Nothing is modified.
pool
Creates or updates in the "pooling" directory a virtual view of all
the files of your disk array.

View file

@ -18,7 +18,7 @@ snapraid [-c, --conf CONFIG]
[-S, --start BLKSTART] [-B, --count BLKCOUNT]
[-L, --error-limit NUMBER]
[-v, --verbose]
status|sync|scrub|fix|check|list|diff|dup|pool|rehash
status|diff|sync|scrub|fix|check|list|dup|up|down|pool|rehash
snapraid [-V, --version] [-H, --help] [-C, --gen-conf CONTENT]
@ -401,7 +401,18 @@ Later modifications are not taken into account.
Nothing is modified.
5.2 sync
5.2 diff
--------
Lists all the files modified from the last "sync" that need to have
their parity data recomputed.
This command doesn't check the file data, but only the file timestamp
size and inode.
Nothing is modified.
5.3 sync
--------
Updates the parity information. All the modified files
@ -428,7 +439,7 @@ but the previously compute hash information is kept.
The "content" and "parity" files are modified if necessary.
The files in the array are NOT modified.
5.3 scrub
5.4 scrub
---------
Scrubs the array, checking for silent or input/output errors in data
@ -463,7 +474,7 @@ of each block, and to mark bad blocks.
The "parity" files are NOT modified.
The files in the array are NOT modified.
5.4 fix
5.5 fix
-------
Fix all the files and the parity data.
@ -492,7 +503,7 @@ The "content" file is NOT modified.
The "parity" files are modified if necessary.
The files in the array are modified if necessary.
5.5 check
5.6 check
---------
Verify all the files and the parity data.
@ -512,7 +523,7 @@ Files are identified only by path, and not by inode.
Nothing is modified.
5.6 list
5.7 list
--------
Lists all the files contained in the array at the time of the
@ -520,17 +531,6 @@ last "sync".
Nothing is modified.
5.7 diff
--------
Lists all the files modified from the last "sync" that need to have
their parity data recomputed.
This command doesn't check the file data, but only the file timestamp
size and inode.
Nothing is modified.
5.8 dup
-------
@ -540,8 +540,22 @@ precomputed hashes are used.
Nothing is modified.
5.9 pool
--------
5.9 up
------
Spins up all the disks of the array.
Nothing is modified.
5.10 down
---------
Spins down all the disks of the array.
Nothing is modified.
5.11 pool
---------
Creates or updates in the "pooling" directory a virtual view of all
the files of your disk array.
@ -555,7 +569,7 @@ view of the array. Any other regular file is left in place.
Nothing is modified outside the pool directory.
5.10 rehash
5.12 rehash
-----------
Schedules a rehash of the whole array.

View file

@ -25,14 +25,14 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "cmdline/portable.h"
#include "cmdline/util.h" /* for malloc_nofail() */
/* redefine the malloc for tommy use */
#define tommy_malloc malloc_nofail
#define tommy_calloc calloc_nofail
#define tommy_free free
#include "cmdline/portable.h"
#include "cmdline/util.h" /* for malloc_nofail() */
#include "tommyhash.c"
#include "tommyarray.c"
#include "tommyarrayblk.c"