diff --git a/cmdline/device.c b/cmdline/device.c index 47a06be5..35188293 100644 --- a/cmdline/device.c +++ b/cmdline/device.c @@ -662,7 +662,7 @@ static void state_smart(struct snapraid_state* state, size_t n, tommy_list* low) if (len > serial_pad) serial_pad = len; - if (devinfo->parent && devinfo->parent->is_array) + if (devinfo->is_array) have_array = 1; } @@ -756,10 +756,8 @@ static void state_smart(struct snapraid_state* state, size_t n, tommy_list* low) /* this happens only if no data */ printf(" -"); } else { - int is_array = devinfo->parent && devinfo->parent->is_array; - /* compute failure rate only for array disks (or fallback to all disks if none are array members) */ - if (is_array || !have_array) + if (devinfo->is_array || !have_array) array_failure_rate += afr; printf("%4.0f%%", poisson_prob_at_least_one_failure(afr) * 100); @@ -1032,6 +1030,7 @@ int devtest(tommy_list* high, tommy_list* low, int operation) /* fake device number */ entry->device = tommy_strhash_u32(0, devinfo->name); + entry->is_array = devinfo->is_array; tommy_list_insert_tail(low, &entry->node, entry); @@ -1162,36 +1161,25 @@ int state_device(struct snapraid_state* state, int operation, tommy_list* filter } } - /* extra disks are never spundown or spunup */ - int include_extra = 1; - switch (operation) { - case DEVICE_UP : - case DEVICE_DOWN : - case DEVICE_DOWNIFUP : - include_extra = 0; - break; - } - if (include_extra) { - /* for all extra disks */ - for (i = state->extralist; i != 0; i = i->next) { - struct snapraid_extra* extra = i->data; - devinfo_t* entry; + /* for all extra disks */ + for (i = state->extralist; i != 0; i = i->next) { + struct snapraid_extra* extra = i->data; + devinfo_t* entry; - if (filterlist_disk != 0 && filter_path(filterlist_disk, 0, extra->name, 0) != 0) - continue; + if (filterlist_disk != 0 && filter_path(filterlist_disk, 0, extra->name, 0) != 0) + continue; - entry = calloc_nofail(1, sizeof(devinfo_t)); + entry = calloc_nofail(1, sizeof(devinfo_t)); - entry->device = extra->device; - device_name_set(entry, extra->name, 0); - entry->is_array = 0; - pathcpy(entry->mount, sizeof(entry->mount), extra->dir); - pathcpy(entry->smartctl, sizeof(entry->smartctl), extra->smartctl); - pathcpy(entry->smartctl_info, sizeof(entry->smartctl_info), extra->smartctl_info); - memcpy(entry->smartignore, extra->smartignore, sizeof(entry->smartignore)); + entry->device = extra->device; + device_name_set(entry, extra->name, 0); + entry->is_array = 0; + pathcpy(entry->mount, sizeof(entry->mount), extra->dir); + pathcpy(entry->smartctl, sizeof(entry->smartctl), extra->smartctl); + pathcpy(entry->smartctl_info, sizeof(entry->smartctl_info), extra->smartctl_info); + memcpy(entry->smartignore, extra->smartignore, sizeof(entry->smartignore)); - tommy_list_insert_tail(&high, &entry->node, entry); - } + tommy_list_insert_tail(&high, &entry->node, entry); } /* with a GUI always gives time reference */ @@ -1199,6 +1187,7 @@ int state_device(struct snapraid_state* state, int operation, tommy_list* filter log_tag("unixtime:%" PRIi64 "\n", (int64_t)now); int degraded = 0; + int query_failed = 0; if (state->opt.fake_device) { ret = devtest(&high, &low, operation); @@ -1211,6 +1200,10 @@ int state_device(struct snapraid_state* state, int operation, tommy_list* filter if (ret > 0) { degraded = 1; ret = 0; + } else if (ret < 0 && !tommy_list_empty(&low)) { + /* keep operating on devices resolved before or after a failed disk */ + query_failed = 1; + ret = 0; } } @@ -1259,6 +1252,8 @@ bail: if (ret == 0 && degraded) ret = 1; + if (ret == 0 && query_failed) + ret = -1; return ret; } diff --git a/cmdline/mingwapp.c b/cmdline/mingwapp.c index 880d080a..cad6fc48 100644 --- a/cmdline/mingwapp.c +++ b/cmdline/mingwapp.c @@ -1049,6 +1049,7 @@ static int devtree(devinfo_t* parent, tommy_list* list) pathprint(devinfo->file, sizeof(devinfo->file), "/dev/pd%" PRIu64, devinfo->device); pathprint(devinfo->wfile, sizeof(devinfo->wfile), "\\\\.\\PhysicalDrive%" PRIu64, devinfo->device); devinfo->parent = parent; + devinfo->is_array = parent->is_array; /* insert in the list */ tommy_list_insert_tail(list, &devinfo->node, devinfo); @@ -1959,27 +1960,34 @@ static int devup(uint64_t device, const char* name, const char* wfile) static void* thread_spinup(void* arg) { devinfo_t* devinfo = arg; - uint64_t start; + int ret; - /* skip not rotational devices */ - if (devpower(devinfo->device, devinfo->name, devinfo->wfile) == 0) - return 0; + /* only for members of the array and rotational devices */ + if (devinfo->is_array && devpower(devinfo->device, devinfo->name, devinfo->wfile) != 0) { + uint64_t start = os_tick_ms(); - start = os_tick_ms(); + if (devup(devinfo->device, devinfo->name, devinfo->wfile) != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } - if (devup(devinfo->device, devinfo->name, devinfo->wfile) != 0) { - /* LCOV_EXCL_START */ - return (void*)-1; - /* LCOV_EXCL_STOP */ - } + msg_status("Spunup device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); - msg_status("Spunup device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); - - /* after the spin up, get SMART info */ - if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smartctl_info, devinfo->smart, devinfo->info, devinfo->serial, devinfo->family, devinfo->model, devinfo->interf) != 0) { - /* LCOV_EXCL_START */ - return (void*)-1; - /* LCOV_EXCL_STOP */ + ret = devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smartctl_info, devinfo->smart, devinfo->info, devinfo->serial, devinfo->family, devinfo->model, devinfo->interf); + if (ret != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } + } else { + /* just probe others */ + ret = devprobe(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smartctl_info, &devinfo->power, devinfo->smart, devinfo->info, devinfo->serial, devinfo->family, devinfo->model, devinfo->interf); + if (ret != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } } /* @@ -1999,22 +2007,20 @@ static void* thread_spinup(void* arg) static void* thread_spindown(void* arg) { devinfo_t* devinfo = arg; - uint64_t start; - /* skip not rotational devices */ - if (devpower(devinfo->device, devinfo->name, devinfo->wfile) == 0) - return 0; + /* only for members of the array and rotational devices */ + if (devinfo->is_array && devpower(devinfo->device, devinfo->name, devinfo->wfile) != 0) { + uint64_t start = os_tick_ms(); - start = os_tick_ms(); + if (devdown(devinfo->device, devinfo->name, devinfo->smartctl) != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } - if (devdown(devinfo->device, devinfo->name, devinfo->smartctl) != 0) { - /* LCOV_EXCL_START */ - return (void*)-1; - /* LCOV_EXCL_STOP */ + msg_status("Spundown device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); } - msg_status("Spundown device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); - return 0; } @@ -2024,24 +2030,22 @@ static void* thread_spindown(void* arg) static void* thread_spindownifup(void* arg) { devinfo_t* devinfo = arg; - uint64_t start; - int power; - /* skip not rotational devices */ - if (devpower(devinfo->device, devinfo->name, devinfo->wfile) == 0) - return 0; + /* only for members of the array and rotational devices */ + if (devinfo->is_array && devpower(devinfo->device, devinfo->name, devinfo->wfile) != 0) { + uint64_t start = os_tick_ms(); + int power; - start = os_tick_ms(); + if (devdownifup(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smartctl_info, &power) != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } - if (devdownifup(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smartctl_info, &power) != 0) { - /* LCOV_EXCL_START */ - return (void*)-1; - /* LCOV_EXCL_STOP */ + if (power == POWER_ACTIVE) + msg_status("Spundown device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); } - if (power == POWER_ACTIVE) - msg_status("Spundown device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); - return 0; } @@ -2133,6 +2137,7 @@ void devsync(tommy_list* high) int devquery(tommy_list* high, tommy_list* low) { tommy_node* i; + int failed = 0; /* for each device */ for (i = tommy_list_head(high); i != 0; i = i->next) { @@ -2142,7 +2147,8 @@ int devquery(tommy_list* high, tommy_list* low) if (devresolve(devinfo->mount, devinfo->file, sizeof(devinfo->file), devinfo->wfile, sizeof(devinfo->wfile)) != 0) { /* LCOV_EXCL_START */ log_error(EEXTERNAL, "Failed to resolve path '%s'.\n", devinfo->mount); - return -1; + failed = 1; + continue; /* LCOV_EXCL_STOP */ } @@ -2159,12 +2165,13 @@ int devquery(tommy_list* high, tommy_list* low) if (devtree(devinfo, low) != 0) { /* LCOV_EXCL_START */ log_error(EEXTERNAL, "Failed to expand device '%s'.\n", devinfo->file); - return -1; + failed = 1; + continue; /* LCOV_EXCL_STOP */ } } - return 0; + return failed ? -1 : 0; } int devrun(tommy_list* low, int operation) diff --git a/cmdline/unixapp.c b/cmdline/unixapp.c index e220a9cf..a3e702cb 100644 --- a/cmdline/unixapp.c +++ b/cmdline/unixapp.c @@ -3181,6 +3181,7 @@ static int devtree(devinfo_t* parent, dev_t device, tommy_list* list, int* degra char path[PATH_MAX]; DIR* d; int slaves = 0; + int failed = 0; /* check if this device or parent partition is a degraded MD array */ pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/md/degraded", major(device), minor(device)); @@ -3201,6 +3202,7 @@ static int devtree(devinfo_t* parent, dev_t device, tommy_list* list, int* degra while ((dd = readdir(d)) != 0) { if (dd->d_name[0] != '.') { dev_t subdev; + ++slaves; /* 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); @@ -3208,19 +3210,17 @@ static int devtree(devinfo_t* parent, dev_t device, tommy_list* list, int* degra subdev = devread(path); if (!subdev) { /* LCOV_EXCL_START */ - closedir(d); - return -1; + failed = 1; + continue; /* LCOV_EXCL_STOP */ } if (devtree(parent, subdev, list, degraded) != 0) { /* LCOV_EXCL_START */ - closedir(d); - return -1; + failed = 1; + continue; /* LCOV_EXCL_STOP */ } - - ++slaves; } } @@ -3263,12 +3263,14 @@ static int devtree(devinfo_t* parent, dev_t device, tommy_list* list, int* degra memcpy(devinfo->smartignore, parent->smartignore, sizeof(devinfo->smartignore)); pathcpy(devinfo->file, sizeof(devinfo->file), path); devinfo->parent = parent; + devinfo->is_array = parent->is_array; /* insert in the list */ tommy_list_insert_tail(list, &devinfo->node, devinfo); } - return 0; + /* retain resolved siblings even when another branch failed */ + return failed ? -1 : 0; } #endif @@ -3896,27 +3898,34 @@ static void* thread_spinup(void* arg) { #if HAVE_LINUX_DEVICE devinfo_t* devinfo = arg; - uint64_t start; + int ret; - /* skip not rotational devices */ - if (devpower(devinfo->device) == 0) - return 0; + /* only for members of the array and rotational devices */ + if (devinfo->is_array && devpower(devinfo->device) != 0) { + uint64_t start = os_tick_ms(); - start = os_tick_ms(); + if (devup(devinfo->device, devinfo->name) != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } - if (devup(devinfo->device, devinfo->name) != 0) { - /* LCOV_EXCL_START */ - return (void*)-1; - /* LCOV_EXCL_STOP */ - } + msg_status("Spunup device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); - msg_status("Spunup device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); - - /* after the spin up, get SMART info */ - if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smartctl_info, devinfo->smart, devinfo->info, devinfo->serial, devinfo->family, devinfo->model, devinfo->interf) != 0) { - /* LCOV_EXCL_START */ - return (void*)-1; - /* LCOV_EXCL_STOP */ + ret = devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smartctl_info, devinfo->smart, devinfo->info, devinfo->serial, devinfo->family, devinfo->model, devinfo->interf); + if (ret != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } + } else { + /* just probe others */ + ret = devprobe(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smartctl_info, &devinfo->power, devinfo->smart, devinfo->info, devinfo->serial, devinfo->family, devinfo->model, devinfo->interf); + if (ret != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } } /* @@ -3941,22 +3950,20 @@ static void* thread_spindown(void* arg) { #if HAVE_LINUX_DEVICE devinfo_t* devinfo = arg; - uint64_t start; - /* skip not rotational devices */ - if (devpower(devinfo->device) == 0) - return 0; + /* only for members of the array and rotational devices */ + if (devinfo->is_array && devpower(devinfo->device) != 0) { + uint64_t start = os_tick_ms(); - start = os_tick_ms(); + if (devdown(devinfo->device, devinfo->name, devinfo->smartctl) != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } - if (devdown(devinfo->device, devinfo->name, devinfo->smartctl) != 0) { - /* LCOV_EXCL_START */ - return (void*)-1; - /* LCOV_EXCL_STOP */ + msg_status("Spundown device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); } - msg_status("Spundown device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); - return 0; #else (void)arg; @@ -3971,24 +3978,22 @@ static void* thread_spindownifup(void* arg) { #if HAVE_LINUX_DEVICE devinfo_t* devinfo = arg; - uint64_t start; - int power; - /* skip not rotational devices */ - if (devpower(devinfo->device) == 0) - return 0; + /* only for members of the array and rotational devices */ + if (devinfo->is_array && devpower(devinfo->device) != 0) { + uint64_t start = os_tick_ms(); + int power; - start = os_tick_ms(); + if (devdownifup(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smartctl_info, &power) != 0) { + /* LCOV_EXCL_START */ + return (void*)-1; + /* LCOV_EXCL_STOP */ + } - if (devdownifup(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smartctl_info, &power) != 0) { - /* LCOV_EXCL_START */ - return (void*)-1; - /* LCOV_EXCL_STOP */ + if (power == POWER_ACTIVE) + msg_status("Spundown device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); } - if (power == POWER_ACTIVE) - msg_status("Spundown device '%s' for disk '%s' in %" PRIu64 " ms.\n", devinfo->file, devinfo->name, os_tick_ms() - start); - return 0; #else (void)arg; @@ -4103,6 +4108,10 @@ void devsync(tommy_list* high) devinfo_t* devinfo = i->data; int f; + /* only for members of the array */ + if (!devinfo->is_array) + continue; + f = open(devinfo->mount, O_RDONLY); if (f >= 0) { syncfs(f); @@ -4117,6 +4126,7 @@ void devsync(tommy_list* high) int devquery(tommy_list* high, tommy_list* low) { int degraded = 0; + int failed = 0; #if HAVE_LINUX_DEVICE tommy_node* i; struct stat st; @@ -4142,7 +4152,8 @@ int devquery(tommy_list* high, tommy_list* low) if (ret < 0) { /* LCOV_EXCL_START */ log_error(EEXTERNAL, "Failed to dereference device '%u:%u' at '%s'.\n", major(device), minor(device), devinfo->mount); - return -1; + failed = 1; + continue; /* LCOV_EXCL_STOP */ } @@ -4167,7 +4178,8 @@ int devquery(tommy_list* high, tommy_list* low) if (devresolve(dev->device, file, sizeof(file)) != 0) { /* LCOV_EXCL_START */ log_error(EEXTERNAL, "Failed to resolve device '%u:%u'.\n", major(dev->device), minor(dev->device)); - return -1; + failed = 1; + continue; /* LCOV_EXCL_STOP */ } @@ -4180,7 +4192,8 @@ int devquery(tommy_list* high, tommy_list* low) if (devtree(devinfo, dev->device, low, &disk_degraded) != 0) { /* LCOV_EXCL_START */ log_error(EEXTERNAL, "Failed to expand device '%u:%u'.\n", major(dev->device), minor(dev->device)); - return -1; + failed = 1; + continue; /* LCOV_EXCL_STOP */ } } @@ -4198,7 +4211,7 @@ int devquery(tommy_list* high, tommy_list* low) (void)low; #endif - return degraded ? 1 : 0; + return failed ? -1 : degraded ? 1 : 0; } int devrun(tommy_list* low, int operation)