diff --git a/cmdline/device.c b/cmdline/device.c index ec334028..d8fa8865 100644 --- a/cmdline/device.c +++ b/cmdline/device.c @@ -912,7 +912,30 @@ static void state_stat(struct snapraid_state* state, tommy_list* high) /* print disk access_stat (not split) */ if (devinfo->split == 0 && devinfo->access_stat != 0) { - log_tag("stat:%s:%" PRIu64 "\n", devinfo->name, devinfo->access_stat); + if (devinfo->name[0]) + log_tag("stat:%s:%" PRIu64 "\n", devinfo->name, devinfo->access_stat); + else + log_tag("stat_device:%s:%" PRIu64 "\n", devinfo->file, devinfo->access_stat); + } + } +} + +static void state_devices(struct snapraid_state* state, tommy_list* low) +{ + tommy_node* i; + + (void)state; + + for (i = tommy_list_head(low); i != 0; i = i->next) { + devinfo_t* devinfo = i->data; + devinfo_t* parent = devinfo->parent; + + if (parent) { +#ifdef _WIN32 + printf("%" PRIu64 "\t%s\t%08" PRIx64 "\t%s\t%s\n", devinfo->device, devinfo->wfile, parent->device, parent->wfile, parent->name); +#else + printf("%u:%u\t%s\t%u:%u\t%s\t%s\n", major(devinfo->device), minor(devinfo->device), devinfo->file, major(parent->device), minor(parent->device), parent->file, parent->name); +#endif } } } @@ -1058,7 +1081,7 @@ void state_device(struct snapraid_state* state, int operation, tommy_list* filte if (state->opt.fake_device) { ret = devtest(&high, &low, operation); } else { - int others = operation == DEVICE_SMART || operation == DEVICE_PROBE; + int others = operation == DEVICE_SMART || operation == DEVICE_PROBE || operation == DEVICE_LIST; ret = devquery(&high, &low, operation, others); } @@ -1079,19 +1102,8 @@ void state_device(struct snapraid_state* state, int operation, tommy_list* filte } log_fatal(ESOFT, "%s is unsupported in this platform.\n", ope); } else { - if (operation == DEVICE_LIST) { - for (i = tommy_list_head(&low); i != 0; i = i->next) { - devinfo_t* devinfo = i->data; - devinfo_t* parent = devinfo->parent; -#ifdef _WIN32 - printf("%" PRIu64 "\t%s\t%08" PRIx64 "\t%s\t%s\n", devinfo->device, devinfo->wfile, parent->device, parent->wfile, parent->name); -#else - printf("%u:%u\t%s\t%u:%u\t%s\t%s\n", major(devinfo->device), minor(devinfo->device), devinfo->file, major(parent->device), minor(parent->device), parent->file, parent->name); -#endif - } - } - state_stat(state, &high); + state_stat(state, &low); if (operation == DEVICE_SMART) state_smart(state, state->level + tommy_list_count(&state->disklist), &low); @@ -1101,6 +1113,9 @@ void state_device(struct snapraid_state* state, int operation, tommy_list* filte if (operation == DEVICE_UP) state_attr(state, &low); + + if (operation == DEVICE_LIST) + state_devices(state, &low); } tommy_list_foreach(&high, free); diff --git a/cmdline/portable.h b/cmdline/portable.h index 52f82c87..65b7e816 100644 --- a/cmdline/portable.h +++ b/cmdline/portable.h @@ -539,7 +539,7 @@ struct devinfo_struct { char wfile[PATH_MAX]; /**< File device in Windows format. Like \\.\PhysicalDriveX, or \\?\Volume{X}. */ #endif struct devinfo_struct* parent; /**< Pointer at the parent if any. */ - struct devinfo_struct* split; /**< Pointer at first split if any. */ + struct devinfo_struct* split; /**< Pointer at first split if this one is not the first. */ struct smart_attr smart[SMART_COUNT]; /**< All smart values. */ uint64_t info[INFO_COUNT]; /**< Informational attributes not related to SMART telemetry. */ uint64_t access_stat; /**< Access stat info. */ diff --git a/cmdline/unix.c b/cmdline/unix.c index b01c4263..d43ca948 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -1397,6 +1397,79 @@ static int devtree(devinfo_t* parent, dev_t device, tommy_list* list) } #endif +/** + * Compute disk usage by aggregating access statistics. + */ +#if HAVE_LINUX_DEVICE +static int devstat(dev_t device, uint64_t* count) +{ + char path[PATH_MAX]; + char buf[512]; + int token; + int ret; + char* i; + + *count = 0; + + pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/stat", major(device), minor(device)); + + ret = sysread(path, buf, sizeof(buf)); + if (ret < 0) { + /* LCOV_EXCL_START */ + log_fatal(errno, "Failed to read '%s'.\n", path); + return -1; + /* LCOV_EXCL_STOP */ + } + if ((size_t)ret + 1 > sizeof(buf)) { + /* LCOV_EXCL_START */ + log_fatal(EEXTERNAL, "Too long read '%s'.\n", path); + return -1; + /* LCOV_EXCL_STOP */ + } + + /* ending 0 */ + buf[ret] = 0; + + i = buf; + token = 1; /* token number */ + while (*i) { + char* n; + char* e; + unsigned long long v; + + /* skip spaces */ + while (*i && isspace(*i)) + ++i; + + /* read digits */ + n = i; + while (*i && isdigit(*i)) + ++i; + + if (i == n) /* if no digit, abort */ + break; + if (*i == 0 || !isspace(*i)) /* if no space, abort */ + break; + *i++ = 0; /* put a terminator */ + + v = strtoull(n, &e, 10); + if (*e != 0) + break; + + /* sum reads and writes completed */ + if (token == 1 || token == 5) { + *count += v; + if (token == 5) + break; /* stop here */ + } + + ++token; + } + + return 0; +} +#endif + /** * Scan all the devices. * @@ -1469,6 +1542,13 @@ static int devscan(tommy_list* list) devinfo->device = device; pathcpy(devinfo->file, sizeof(devinfo->file), path); + /* retrieve access stat for the low level device */ + uint64_t access_stat; + if (devstat(device, &access_stat) == 0) { + /* cumulate access stat in the first split */ + devinfo->access_stat = access_stat; + } + /* insert in the list */ tommy_list_insert_tail(list, &devinfo->node, devinfo); } @@ -1559,79 +1639,6 @@ static int devsmart(dev_t device, const char* name, const char* smartctl, struct } #endif -/** - * Compute disk usage by aggregating access statistics. - */ -#if HAVE_LINUX_DEVICE -static int devstat(dev_t device, uint64_t* count) -{ - char path[PATH_MAX]; - char buf[512]; - int token; - int ret; - char* i; - - *count = 0; - - pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/stat", major(device), minor(device)); - - ret = sysread(path, buf, sizeof(buf)); - if (ret < 0) { - /* LCOV_EXCL_START */ - log_fatal(errno, "Failed to read '%s'.\n", path); - return -1; - /* LCOV_EXCL_STOP */ - } - if ((size_t)ret + 1 > sizeof(buf)) { - /* LCOV_EXCL_START */ - log_fatal(EEXTERNAL, "Too long read '%s'.\n", path); - return -1; - /* LCOV_EXCL_STOP */ - } - - /* ending 0 */ - buf[ret] = 0; - - i = buf; - token = 1; /* token number */ - while (*i) { - char* n; - char* e; - unsigned long long v; - - /* skip spaces */ - while (*i && isspace(*i)) - ++i; - - /* read digits */ - n = i; - while (*i && isdigit(*i)) - ++i; - - if (i == n) /* if no digit, abort */ - break; - if (*i == 0 || !isspace(*i)) /* if no space, abort */ - break; - *i++ = 0; /* put a terminator */ - - v = strtoull(n, &e, 10); - if (*e != 0) - break; - - /* sum reads and writes completed */ - if (token == 1 || token == 5) { - *count += v; - if (token == 5) - break; /* stop here */ - } - - ++token; - } - - return 0; -} -#endif - /** * Get device attributes. */ @@ -2210,7 +2217,7 @@ int devquery(tommy_list* high, tommy_list* low, int operation, int others) /* LCOV_EXCL_STOP */ } - /* for each device */ + /* for each high device */ for (i = tommy_list_head(high); i != 0; i = i->next) { devinfo_t* devinfo = i->data; uint64_t device = devinfo->device; @@ -2273,6 +2280,7 @@ int devquery(tommy_list* high, tommy_list* low, int operation, int others) /* LCOV_EXCL_STOP */ } } + #else (void)high; (void)others;