mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-26 19:01:57 -04:00
Add disk usage detection based on access counters
This commit is contained in:
parent
75b6170b79
commit
986d7464b4
7 changed files with 222 additions and 1 deletions
3
HISTORY
3
HISTORY
|
|
@ -6,7 +6,8 @@ SnapRAID HISTORY
|
|||
* Added detection of `smartctl` executable. Improves reliability when running
|
||||
under `sudo` or environments where `/sbin` and `/usr/sbin` are not in PATH.
|
||||
* Avoided saving the content file when it was not strictly necessary.
|
||||
* More log tags for the `status` command [Tristan Teufel]
|
||||
* More log tags for the `status` command [Tristan Teufel].
|
||||
* More log tags for the `probe` command.
|
||||
* Added documentation of the tags used in the log file in the new
|
||||
snapraid_log manpage.
|
||||
* Added manual translations in multiple languages.
|
||||
|
|
|
|||
|
|
@ -558,6 +558,8 @@ static void state_info_log(devinfo_t* devinfo)
|
|||
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]);
|
||||
if (devinfo->access_stat != 0)
|
||||
log_tag("attr:%s:%s:stat:%" PRIu64 "\n", devinfo->file, devinfo->name, devinfo->access_stat);
|
||||
}
|
||||
|
||||
static void state_smart_log(devinfo_t* devinfo, double afr)
|
||||
|
|
|
|||
|
|
@ -520,6 +520,7 @@ struct devinfo_struct {
|
|||
struct devinfo_struct* parent; /**< Pointer at the parent if any. */
|
||||
uint64_t smart[SMART_COUNT]; /**< SMART attributes. */
|
||||
uint64_t info[INFO_COUNT]; /**< Info attributes. */
|
||||
uint64_t access_stat; /**< Access stat. */
|
||||
char serial[SMART_MAX]; /**< Serial number. */
|
||||
char family[SMART_MAX]; /**< Family. */
|
||||
char model[SMART_MAX]; /**< Model. */
|
||||
|
|
|
|||
191
cmdline/unix.c
191
cmdline/unix.c
|
|
@ -1274,6 +1274,192 @@ static int devsmart(dev_t device, const char* name, const char* smartctl, uint64
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Compute disk usage by aggregating access statistics.
|
||||
*
|
||||
* This function determines whether a disk has been used by summing read
|
||||
* and write access counters from all related partitions and device holders.
|
||||
* Disk-level statistics are not used directly, as they may include
|
||||
* kernel-generated fake accesses that do not reflect real I/O activity.
|
||||
*
|
||||
* By walking the device hierarchy and accumulating per-device statistics,
|
||||
* the function provides a reliable measure of actual disk usage between
|
||||
* sampling points.
|
||||
*/
|
||||
#if HAVE_LINUX_DEVICE
|
||||
static int devstat_recurse(dev_t device, uint64_t* count)
|
||||
{
|
||||
char device_path[PATH_MAX];
|
||||
char path[PATH_MAX];
|
||||
char buf[512];
|
||||
char* device_file;
|
||||
int device_len;
|
||||
DIR* d;
|
||||
struct dirent* dd;
|
||||
int holders = 0;
|
||||
int partitions = 0;
|
||||
int token;
|
||||
int ret;
|
||||
char* i;
|
||||
|
||||
/* get the device name */
|
||||
if (devresolve(device, device_path, sizeof(device_path)) != 0)
|
||||
return -1;
|
||||
|
||||
device_len = strlen(device_path);
|
||||
if (device_len <= 5)
|
||||
return -1;
|
||||
device_file = device_path + 5; /* skip /dev/ */
|
||||
device_len -= 5;
|
||||
|
||||
pathprint(path, sizeof(path), "/sys/dev/block/%u:%u", major(device), minor(device));
|
||||
|
||||
/* check if there are partitions */
|
||||
d = opendir(path);
|
||||
if (d == 0)
|
||||
return -1;
|
||||
|
||||
while ((dd = readdir(d)) != 0) {
|
||||
dev_t subdev;
|
||||
|
||||
if (dd->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
if (strncmp(device_file, dd->d_name, device_len) != 0)
|
||||
continue;
|
||||
|
||||
pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/%s/dev", major(device), minor(device), dd->d_name);
|
||||
|
||||
subdev = devread(path);
|
||||
if (!subdev) {
|
||||
/* LCOV_EXCL_START */
|
||||
closedir(d);
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (devstat_recurse(subdev, count) != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
closedir(d);
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
++partitions;
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
/* stop if processed partitions */
|
||||
if (partitions != 0)
|
||||
return 0;
|
||||
|
||||
pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/holders", major(device), minor(device));
|
||||
|
||||
/* check if there are holders */
|
||||
d = opendir(path);
|
||||
if (d == 0)
|
||||
return -1;
|
||||
|
||||
while ((dd = readdir(d)) != 0) {
|
||||
dev_t subdev;
|
||||
|
||||
if (dd->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
|
||||
/* for each slave, expand the full potential tree */
|
||||
pathprint(path, sizeof(path), "/sys/dev/block/%u:%u/holders/%s/dev", major(device), minor(device), dd->d_name);
|
||||
|
||||
subdev = devread(path);
|
||||
if (!subdev) {
|
||||
/* LCOV_EXCL_START */
|
||||
closedir(d);
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (devstat_recurse(subdev, count) != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
closedir(d);
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
++holders;
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
|
||||
/* stop if processed holders */
|
||||
if (holders != 0)
|
||||
return 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("Failed to read '%s'.\n", path);
|
||||
return -1;
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
if ((size_t)ret + 1 > sizeof(buf)) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("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;
|
||||
}
|
||||
|
||||
static int devstat(dev_t device, uint64_t* count)
|
||||
{
|
||||
*count = 0;
|
||||
return devstat_recurse(device, count);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get device attributes.
|
||||
*/
|
||||
|
|
@ -1731,6 +1917,11 @@ static void* thread_probe(void* arg)
|
|||
*/
|
||||
devattr(devinfo->device, devinfo->info, devinfo->serial, devinfo->family, devinfo->model);
|
||||
|
||||
/*
|
||||
* Retrieve access stat for the device
|
||||
*/
|
||||
devstat(devinfo->device, &devinfo->access_stat);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
(void)arg;
|
||||
|
|
|
|||
|
|
@ -1592,6 +1592,18 @@ read.
|
|||
.B attr:<device_file>:<disk_name>[/<split_index>]:power:down
|
||||
Logs a successful spin\-down operation initiated via the
|
||||
smartctl command.
|
||||
.TP
|
||||
.B attr:<device_file>:<disk_name>[/<split_index>]:stat:<access_number>
|
||||
Logs the total number of read and write accesses done on the disk.
|
||||
Comparing this number at different times, you can detect if the
|
||||
disk was used during that time.
|
||||
.RS 4
|
||||
.PD 0
|
||||
.HP 4
|
||||
.I <access_number>
|
||||
Total number of accesses (int64).
|
||||
.PD
|
||||
.RE
|
||||
.SS Summary
|
||||
Tags logging the overall failure probabilities for the array.
|
||||
.TP
|
||||
|
|
|
|||
|
|
@ -1016,6 +1016,13 @@ Command Smart Tags
|
|||
Logs a successful spin-down operation initiated via the
|
||||
smartctl command.
|
||||
|
||||
=attr:<device_file>:<disk_name>[/<split_index>]:stat:<access_number>
|
||||
Logs the total number of read and write accesses done on the disk.
|
||||
Comparing this number at different times, you can detect if the
|
||||
disk was used during that time.
|
||||
|
||||
<access_number> - Total number of accesses (int64).
|
||||
|
||||
Summary
|
||||
Tags logging the overall failure probabilities for the array.
|
||||
|
||||
|
|
|
|||
|
|
@ -1058,6 +1058,13 @@ Tags logging specific disk identification and attribute values.
|
|||
Logs a successful spin-down operation initiated via the
|
||||
smartctl command.
|
||||
|
||||
attr:<device_file>:<disk_name>[/<split_index>]:stat:<access_number>
|
||||
Logs the total number of read and write accesses done on the disk.
|
||||
Comparing this number at different times, you can detect if the
|
||||
disk was used during that time.
|
||||
|
||||
<access_number> - Total number of accesses (int64).
|
||||
|
||||
---- 14.0.2 Summary ----
|
||||
Tags logging the overall failure probabilities for the array.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue