From b24807704ea80fd76420c40adc2e0f9eeceec8a3 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Fri, 2 Jan 2015 15:53:15 +0100 Subject: [PATCH] Adds preliminary support for spinning up and down commands. --- HISTORY | 2 + Makefile.am | 4 + cmdline/mingw.c | 8 + cmdline/portable.h | 33 ++++ cmdline/snapraid.c | 37 +++- cmdline/state.h | 5 + cmdline/unix.c | 459 +++++++++++++++++++++++++++++++++++++++++++++ cmdline/util.c | 9 + cmdline/util.h | 5 + configure.ac | 9 +- snapraid.1 | 26 ++- snapraid.d | 30 ++- snapraid.txt | 54 ++++-- tommyds/tommy.c | 6 +- 14 files changed, 640 insertions(+), 47 deletions(-) diff --git a/HISTORY b/HISTORY index a2edb25e..3d3262fe 100644 --- a/HISTORY +++ b/HISTORY @@ -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. diff --git a/Makefile.am b/Makefile.am index e4ba2d9c..44d39bba 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/cmdline/mingw.c b/cmdline/mingw.c index c36bdc1a..40af7369 100644 --- a/cmdline/mingw.c +++ b/cmdline/mingw.c @@ -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 diff --git a/cmdline/portable.h b/cmdline/portable.h index 9566b64c..4f910254 100644 --- a/cmdline/portable.h +++ b/cmdline/portable.h @@ -162,6 +162,10 @@ #include "fnmatch.h" #endif +#if HAVE_PTHREAD_H +#include +#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 diff --git a/cmdline/snapraid.c b/cmdline/snapraid.c index bf1ef9ab..675b7d81 100644 --- a/cmdline/snapraid.c +++ b/cmdline/snapraid.c @@ -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); diff --git a/cmdline/state.h b/cmdline/state.h index b70143c9..4a6b40be 100644 --- a/cmdline/state.h +++ b/cmdline/state.h @@ -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. */ diff --git a/cmdline/unix.c b/cmdline/unix.c index 0ed89e35..304ddaa4 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -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; diff --git a/cmdline/util.c b/cmdline/util.c index 0d924daa..ef6ef0a5 100644 --- a/cmdline/util.c +++ b/cmdline/util.c @@ -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 diff --git a/cmdline/util.h b/cmdline/util.h index b6b952fb..8f99990c 100644 --- a/cmdline/util.h +++ b/cmdline/util.h @@ -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 /. diff --git a/configure.ac b/configure.ac index 2078ac7b..a2af5a16 100644 --- a/configure.ac +++ b/configure.ac @@ -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" ], []) diff --git a/snapraid.1 b/snapraid.1 index da304019..f04cfb93 100644 --- a/snapraid.1 +++ b/snapraid.1 @@ -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. diff --git a/snapraid.d b/snapraid.d index 36224aab..42c20e49 100644 --- a/snapraid.d +++ b/snapraid.d @@ -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. diff --git a/snapraid.txt b/snapraid.txt index dead1891..0a9aeabb 100644 --- a/snapraid.txt +++ b/snapraid.txt @@ -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. diff --git a/tommyds/tommy.c b/tommyds/tommy.c index 53ece8c2..b69d9de1 100644 --- a/tommyds/tommy.c +++ b/tommyds/tommy.c @@ -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"