Log disk information info also in probe
Some checks failed
Build / build-mac (push) Has been cancelled
Build / build-linux (push) Has been cancelled
Build / build-win (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled

This commit is contained in:
Andrea Mazzoleni 2025-12-18 18:16:02 +01:00
parent 1759716734
commit 1f17ceca84
6 changed files with 117 additions and 70 deletions

View file

@ -535,6 +535,41 @@ static double raid_prob_of_one_or_more_failures(double array_failure_rate, doubl
return poisson_prob_n_or_more_failures(raid_failure_rate, 1);
}
static void state_info_log(devinfo_t* devinfo)
{
char esc_buffer[ESC_MAX];
log_tag("info:%s:%s\n", devinfo->file, devinfo->name);
if (devinfo->serial[0])
log_tag("attr:%s:%s:serial:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->serial, esc_buffer));
if (devinfo->vendor[0])
log_tag("attr:%s:%s:vendor:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->vendor, esc_buffer));
if (devinfo->model[0])
log_tag("attr:%s:%s:model:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->model, esc_buffer));
if (devinfo->info[INFO_SIZE] != SMART_UNASSIGNED)
log_tag("attr:%s:%s:size:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->info[INFO_SIZE]);
if (devinfo->info[INFO_ROTATION_RATE] != SMART_UNASSIGNED)
log_tag("attr:%s:%s:rotationrate:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->info[INFO_ROTATION_RATE]);
}
static void state_smart_log(devinfo_t* devinfo, double afr)
{
unsigned j;
log_tag("smart:%s:%s\n", devinfo->file, devinfo->name);
if (devinfo->smart[SMART_ERROR] != SMART_UNASSIGNED)
log_tag("attr:%s:%s:error:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_ERROR]);
if (devinfo->smart[SMART_FLAGS] != SMART_UNASSIGNED)
log_tag("attr:%s:%s:flags:%" PRIu64 ":%" PRIx64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_FLAGS], devinfo->smart[SMART_FLAGS]);
if (afr != 0)
log_tag("attr:%s:%s:afr:%g:%g\n", devinfo->file, devinfo->name, afr, poisson_prob_n_or_more_failures(afr, 1));
for (j = 0; j < 256; ++j)
if (devinfo->smart[j] != SMART_UNASSIGNED)
log_tag("attr:%s:%s:%u:%" PRIu64 ":%" PRIx64 "\n", devinfo->file, devinfo->name, j, devinfo->smart[j], devinfo->smart[j]);
}
static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* low)
{
tommy_node* i;
@ -547,7 +582,6 @@ static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* lo
int make_it_fail = 0;
uint64_t mask32 = 0xffffffffU;
uint64_t mask16 = 0xffffU;
char esc_buffer[ESC_MAX];
/* compute lengths for padding */
device_pad = 0;
@ -561,7 +595,7 @@ static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* lo
if (len > device_pad)
device_pad = len;
len = strlen(devinfo->smart_serial);
len = strlen(devinfo->serial);
if (len > serial_pad)
serial_pad = len;
@ -646,12 +680,12 @@ static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* lo
/* if error running smartctl, skip AFR estimation */
afr = 0;
printf(" n/a");
} else if (devinfo->smart[SMART_ROTATION_RATE] == 0) {
} else if (devinfo->info[INFO_ROTATION_RATE] == 0) {
/* if SSD, skip AFR estimation as data is from not SSD disks */
afr = 0;
printf(" SSD");
} else {
afr = smart_afr(devinfo->smart, devinfo->smart_model);
afr = smart_afr(devinfo->smart, devinfo->model);
if (afr == 0) {
/* this happens only if no data */
@ -665,14 +699,14 @@ static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* lo
}
}
if (devinfo->smart[SMART_SIZE] != SMART_UNASSIGNED)
printf(" %4.1f", devinfo->smart[SMART_SIZE] / 1E12);
if (devinfo->info[INFO_SIZE] != SMART_UNASSIGNED)
printf(" %4.1f", devinfo->info[INFO_SIZE] / 1E12);
else
printf(" -");
printf(" ");
if (*devinfo->smart_serial)
printl(devinfo->smart_serial, serial_pad);
if (*devinfo->serial)
printl(devinfo->serial, serial_pad);
else
printl("-", serial_pad);
@ -690,26 +724,8 @@ static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* lo
printf("\n");
log_tag("smart:%s:%s\n", devinfo->file, devinfo->name);
if (devinfo->smart_serial[0])
log_tag("attr:%s:%s:serial:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->smart_serial, esc_buffer));
if (devinfo->smart_vendor[0])
log_tag("attr:%s:%s:vendor:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->smart_vendor, esc_buffer));
if (devinfo->smart_model[0])
log_tag("attr:%s:%s:model:%s\n", devinfo->file, devinfo->name, esc_tag(devinfo->smart_model, esc_buffer));
if (afr != 0)
log_tag("attr:%s:%s:afr:%g:%g\n", devinfo->file, devinfo->name, afr, poisson_prob_n_or_more_failures(afr, 1));
if (devinfo->smart[SMART_SIZE] != SMART_UNASSIGNED)
log_tag("attr:%s:%s:size:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_SIZE]);
if (devinfo->smart[SMART_ERROR] != SMART_UNASSIGNED)
log_tag("attr:%s:%s:error:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_ERROR]);
if (devinfo->smart[SMART_ROTATION_RATE] != SMART_UNASSIGNED)
log_tag("attr:%s:%s:rotationrate:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_ROTATION_RATE]);
if (devinfo->smart[SMART_FLAGS] != SMART_UNASSIGNED)
log_tag("attr:%s:%s:flags:%" PRIu64 ":%" PRIx64 "\n", devinfo->file, devinfo->name, devinfo->smart[SMART_FLAGS], devinfo->smart[SMART_FLAGS]);
for (j = 0; j < 256; ++j)
if (devinfo->smart[j] != SMART_UNASSIGNED)
log_tag("attr:%s:%s:%u:%" PRIu64 ":%" PRIx64 "\n", devinfo->file, devinfo->name, j, devinfo->smart[j], devinfo->smart[j]);
state_info_log(devinfo);
state_smart_log(devinfo, afr);
}
printf("\n");
@ -783,6 +799,8 @@ static void state_probe(struct snapraid_state* state, tommy_list* low)
len = strlen(devinfo->file);
if (len > device_pad)
device_pad = len;
state_info_log(devinfo);
}
printf("SnapRAID PROBE report:\n");
@ -860,16 +878,16 @@ int devtest(tommy_list* high, tommy_list* low, int operation)
}
}
pathprint(entry->smart_serial, sizeof(entry->smart_serial), "FAKE_%s", devinfo->smart_serial);
pathprint(entry->smart_vendor, sizeof(entry->smart_vendor), "FAKE_%s", devinfo->smart_vendor);
pathprint(entry->smart_model, sizeof(entry->smart_model), "FAKE_%s", devinfo->smart_model);
pathprint(entry->serial, sizeof(entry->serial), "FAKE_%s", devinfo->serial);
pathprint(entry->vendor, sizeof(entry->vendor), "FAKE_%s", devinfo->vendor);
pathprint(entry->model, sizeof(entry->model), "FAKE_%s", devinfo->model);
pathprint(entry->file, sizeof(entry->name), "FAKE_%s", devinfo->file);
pathcpy(entry->name, sizeof(entry->name), devinfo->name);
entry->smart[SMART_SIZE] = count * TERA;
entry->smart[SMART_ROTATION_RATE] = 7200;
entry->smart[SMART_TEMPERATURE_CELSIUS] = 27;
entry->info[INFO_SIZE] = count * TERA;
entry->info[INFO_ROTATION_RATE] = 7200;
entry->smart[SMART_ERROR] = 0;
entry->smart[SMART_FLAGS] = SMART_UNASSIGNED;
entry->smart[SMART_TEMPERATURE_CELSIUS] = 27;
switch (count) {
case 3 : entry->smart[SMART_ERROR] = 1; break;

View file

@ -2498,7 +2498,7 @@ static int devscan(tommy_list* list)
/**
* Get SMART attributes.
*/
static int devsmart(uint64_t device, const char* name, const char* smartctl, uint64_t* smart, char* serial, char* vendor, char* model)
static int devsmart(uint64_t device, const char* name, const char* smartctl, uint64_t* smart, uint64_t* info, char* serial, char* vendor, char* model)
{
char conv_buf[CONV_MAX];
WCHAR cmd[MAX_PATH + 128];
@ -2532,7 +2532,7 @@ retry:
/* LCOV_EXCL_STOP */
}
if (smartctl_attribute(f, file, name, smart, serial, vendor, model) != 0) {
if (smartctl_attribute(f, file, name, smart, info, serial, vendor, model) != 0) {
/* LCOV_EXCL_START */
pclose(f);
log_tag("device:%s:%s:shell\n", file, name);
@ -2567,8 +2567,8 @@ retry:
*/
if ((ret == 0 || ret == 2)
&& smart[9] == SMART_UNASSIGNED
&& smart[SMART_SIZE] == SMART_UNASSIGNED
&& smart[SMART_ROTATION_RATE] == SMART_UNASSIGNED
&& info[INFO_SIZE] == SMART_UNASSIGNED
&& info[INFO_ROTATION_RATE] == SMART_UNASSIGNED
) {
/* retry using the "sat" type */
snwprintf(cmd, sizeof(cmd), L"\"%lssmartctl.exe\" -a -d sat %s", exedir, file);
@ -2587,7 +2587,7 @@ retry:
/**
* Get POWER state
*/
static int devprobe(uint64_t device, const char* name, const char* smartctl, int* power)
static int devprobe(uint64_t device, const char* name, const char* smartctl, int* power, uint64_t* info, char* serial, char* vendor, char* model)
{
char conv_buf[CONV_MAX];
WCHAR cmd[MAX_PATH + 128];
@ -2621,7 +2621,7 @@ retry:
/* LCOV_EXCL_STOP */
}
if (smartctl_flush(f, file, name) != 0) {
if (smartctl_attribute(f, file, name, 0, info, serial, vendor, model) != 0) {
/* LCOV_EXCL_START */
pclose(f);
log_tag("device:%s:%s:shell\n", file, name);
@ -2770,7 +2770,7 @@ static int devdownifup(uint64_t device, const char* name, const char* smartctl,
{
*power = POWER_UNKNOWN;
if (devprobe(device, name, smartctl, power) != 0)
if (devprobe(device, name, smartctl, power, 0, 0, 0, 0) != 0)
return -1;
if (*power == POWER_ACTIVE)
@ -2918,7 +2918,7 @@ static void* thread_smart(void* arg)
{
devinfo_t* devinfo = arg;
if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->smart_serial, devinfo->smart_vendor, devinfo->smart_model) != 0) {
if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->info, devinfo->serial, devinfo->vendor, devinfo->model) != 0) {
/* LCOV_EXCL_START */
return (void*)-1;
/* LCOV_EXCL_STOP */
@ -2934,7 +2934,7 @@ static void* thread_probe(void* arg)
{
devinfo_t* devinfo = arg;
if (devprobe(devinfo->device, devinfo->name, devinfo->smartctl, &devinfo->power) != 0) {
if (devprobe(devinfo->device, devinfo->name, devinfo->smartctl, &devinfo->power, devinfo->info, devinfo->serial, devinfo->vendor, devinfo->model) != 0) {
/* LCOV_EXCL_START */
return (void*)-1;
/* LCOV_EXCL_STOP */

View file

@ -447,18 +447,25 @@ int randomize(void* ptr, size_t size);
#define SMART_AIRFLOW_TEMPERATURE_CELSIUS 190
#define SMART_TEMPERATURE_CELSIUS 194
/**
* Additional SMART attributes.
*/
#define SMART_ERROR 256 /**< ATA Error count. */
#define SMART_SIZE 257 /**< Size in bytes. */
#define SMART_ROTATION_RATE 258 /**< Rotation speed. 0 for SSD. */
#define SMART_FLAGS 259 /**< Flags returned by smartctl. */
#define SMART_FLAGS 256 /**< Flags returned by smartctl. */
#define SMART_ERROR 257 /**< ATA Error count. */
/**
* SMART attributes count.
*/
#define SMART_COUNT 260
#define SMART_COUNT 258
/**
* Info attributes.
*/
#define INFO_SIZE 0 /**< Size in bytes. */
#define INFO_ROTATION_RATE 1 /**< Rotation speed. 0 for SSD. */
/**
* Info attributes count.
*/
#define INFO_COUNT 2
#define SMART_IGNORE_MAX 4 /**< Max number of ignored smart attributes */
@ -506,10 +513,11 @@ 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. */
uint64_t smart[SMART_COUNT]; /**< SMART raw attributes. */
char smart_serial[SMART_MAX]; /**< SMART serial number. */
char smart_vendor[SMART_MAX]; /**< SMART vendor. */
char smart_model[SMART_MAX]; /**< SMART model. */
uint64_t smart[SMART_COUNT]; /**< SMART attributes. */
uint64_t info[INFO_COUNT]; /**< Info attributes. */
char serial[SMART_MAX]; /**< Serial number. */
char vendor[SMART_MAX]; /**< Vendor. */
char model[SMART_MAX]; /**< Model. */
int power; /**< POWER mode. */
#if HAVE_THREAD
thread_id_t thread;

View file

@ -1610,15 +1610,36 @@ static int smatch(const char* str, const char* pattern)
return 0;
}
int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, char* serial, char* vendor, char* model)
int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, uint64_t* info, char* serial, char* vendor, char* model)
{
unsigned i;
int inside;
uint64_t dummy_smart[SMART_COUNT];
uint64_t dummy_info[INFO_COUNT];
char dummy_serial[SMART_MAX];
char dummy_vendor[SMART_MAX];
char dummy_model[SMART_MAX];
/* preclear attribute */
/* dummy attributes */
if (!smart)
smart = dummy_smart;
if (!info)
info = dummy_info;
if (!serial)
serial = dummy_serial;
if (!vendor)
vendor = dummy_vendor;
if (!model)
model = dummy_model;
/* preclear attributes */
*serial = 0;
*vendor = 0;
*model = 0;
for (i = 0; i < SMART_COUNT; ++i)
smart[i] = SMART_UNASSIGNED;
for (i = 0; i < INFO_COUNT; ++i)
info[i] = SMART_UNASSIGNED;
/* read the file */
inside = 0;
@ -1645,18 +1666,18 @@ int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* sm
inside = 0;
/* common */
} else if (smatch(s, "Rotation Rate: Solid State") == 0) {
smart[SMART_ROTATION_RATE] = 0;
} else if (sscanf(s, "Rotation Rate: %" SCNu64, &smart[SMART_ROTATION_RATE]) == 1) {
info[INFO_ROTATION_RATE] = 0;
} else if (sscanf(s, "Rotation Rate: %" SCNu64, &info[INFO_ROTATION_RATE]) == 1) {
} else if (smatch(s, "User Capacity:") == 0) {
char* begin = strchr(s, ':');
char* end = strstr(s, "bytes");
if (begin != 0 && end != 0 && begin < end) {
char* p;
smart[SMART_SIZE] = 0;
info[INFO_SIZE] = 0;
for (p = begin; p != end; ++p) {
if (isdigit(*p)) {
smart[SMART_SIZE] *= 10;
smart[SMART_SIZE] += *p - '0';
info[INFO_SIZE] *= 10;
info[INFO_SIZE] += *p - '0';
}
}
}

View file

@ -421,7 +421,7 @@ void malloc_fail(size_t size);
* Read smartctl attributes from a stream.
* Return 0 on success.
*/
int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, char* serial, char* vendor, char* model);
int smartctl_attribute(FILE* f, const char* file, const char* name, uint64_t* smart, uint64_t* info, char* serial, char* vendor, char* model);
/**
* Flush smartctl output from a stream.

View file

@ -1140,7 +1140,7 @@ static int devscan(tommy_list* list)
* Get SMART attributes.
*/
#if HAVE_LINUX_DEVICE
static int devsmart(dev_t device, const char* name, const char* smartctl, uint64_t* smart, char* serial, char* vendor, char* model)
static int devsmart(dev_t device, const char* name, const char* smartctl, uint64_t* smart, uint64_t* info, char* serial, char* vendor, char* model)
{
char cmd[PATH_MAX + 64];
char file[PATH_MAX];
@ -1174,7 +1174,7 @@ static int devsmart(dev_t device, const char* name, const char* smartctl, uint64
/* LCOV_EXCL_STOP */
}
if (smartctl_attribute(f, file, name, smart, serial, vendor, model) != 0) {
if (smartctl_attribute(f, file, name, smart, info, serial, vendor, model) != 0) {
/* LCOV_EXCL_START */
pclose(f);
log_tag("device:%s:%s:shell\n", file, name);
@ -1212,7 +1212,7 @@ static int devsmart(dev_t device, const char* name, const char* smartctl, uint64
* Get POWER state.
*/
#if HAVE_LINUX_DEVICE
static int devprobe(dev_t device, const char* name, const char* smartctl, int* power)
static int devprobe(dev_t device, const char* name, const char* smartctl, int* power, uint64_t* info, char* serial, char* vendor, char* model)
{
char cmd[PATH_MAX + 64];
char file[PATH_MAX];
@ -1246,7 +1246,7 @@ static int devprobe(dev_t device, const char* name, const char* smartctl, int* p
/* LCOV_EXCL_STOP */
}
if (smartctl_flush(f, file, name) != 0) {
if (smartctl_attribute(f, file, name, 0, info, serial, vendor, model) != 0) {
/* LCOV_EXCL_START */
pclose(f);
log_tag("device:%s:%s:shell\n", file, name);
@ -1376,7 +1376,7 @@ static int devdownifup(dev_t device, const char* name, const char* smartctl, int
{
*power = POWER_UNKNOWN;
if (devprobe(device, name, smartctl, power) != 0)
if (devprobe(device, name, smartctl, power, 0, 0, 0, 0) != 0)
return -1;
if (*power == POWER_ACTIVE)
@ -1542,7 +1542,7 @@ static void* thread_smart(void* arg)
#if HAVE_LINUX_DEVICE
devinfo_t* devinfo = arg;
if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->smart_serial, devinfo->smart_vendor, devinfo->smart_model) != 0) {
if (devsmart(devinfo->device, devinfo->name, devinfo->smartctl, devinfo->smart, devinfo->info, devinfo->serial, devinfo->vendor, devinfo->model) != 0) {
/* LCOV_EXCL_START */
return (void*)-1;
/* LCOV_EXCL_STOP */
@ -1563,7 +1563,7 @@ static void* thread_probe(void* arg)
#if HAVE_LINUX_DEVICE
devinfo_t* devinfo = arg;
if (devprobe(devinfo->device, devinfo->name, devinfo->smartctl, &devinfo->power) != 0) {
if (devprobe(devinfo->device, devinfo->name, devinfo->smartctl, &devinfo->power, devinfo->info, devinfo->serial, devinfo->vendor, devinfo->model) != 0) {
/* LCOV_EXCL_START */
return (void*)-1;
/* LCOV_EXCL_STOP */