mirror of
https://github.com/amadvance/snapraid.git
synced 2026-10-25 18:40:19 -04:00
Adds a new smartignore option to ignore specific SMART attributes
This commit is contained in:
parent
4c504ab325
commit
8cef686d26
15 changed files with 211 additions and 39 deletions
2
HISTORY
2
HISTORY
|
|
@ -4,6 +4,8 @@ SnapRAID HISTORY
|
|||
12.5 2025/XX
|
||||
============
|
||||
* Add a bandwidth limit option --bw-limit [Allan Clark]
|
||||
* Add a new smartignore configuration option to ignore specific SMART
|
||||
attributes.
|
||||
|
||||
12.4 2025/01
|
||||
============
|
||||
|
|
|
|||
6
TODO
6
TODO
|
|
@ -5,15 +5,13 @@ This is the list of TODO items for SnapRAID.
|
|||
|
||||
- Next
|
||||
|
||||
* Add an option to ignore a specific Smart attribute. This solves PullRequest #17 an #21
|
||||
|
||||
* Support BTRFS subvolumes. Keep track of the subvolumeid, along with the inode, and use it when searching/comparing inodes.
|
||||
The value 0 can be used for the root volume, like a normal filesystem.
|
||||
See: https://github.com/kdave/btrfs-progs/tree/master/libbtrfsutil
|
||||
|
||||
* A "dependents" output option to [--test-fmt file|disk|path|dependents] for LIST.
|
||||
* A "dependents" output option to [--test-fmt file|disk|path|dependents] for LIST.
|
||||
Example, snapraid LIST --test-fmt dependents >FileList_with_dependents.txt
|
||||
The goal is a filelist that, for every file, includes full paths to the dependent files
|
||||
The goal is a filelist that, for every file, includes full paths to the dependent files
|
||||
on other data disks needed to repair that file (in addition to the parity data).
|
||||
|
||||
I created a thread about it here: https://sourceforge.net/p/snapraid/discussion/1677233/thread/6e872fdae0/
|
||||
|
|
|
|||
|
|
@ -605,7 +605,7 @@ 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_smart(unsigned n, tommy_list* low)
|
||||
static void state_smart(struct snapraid_state* state, unsigned n, tommy_list* low)
|
||||
{
|
||||
tommy_node* i;
|
||||
unsigned j;
|
||||
|
|
@ -665,6 +665,12 @@ static void state_smart(unsigned n, tommy_list* low)
|
|||
double afr;
|
||||
uint64_t flag;
|
||||
|
||||
/* clear attributes to ignore */
|
||||
for (j = 0; j < SMART_IGNORE_MAX; ++j) {
|
||||
devinfo->smart[state->smartignore[j]] = SMART_UNASSIGNED;
|
||||
devinfo->smart[devinfo->smartignore[j]] = SMART_UNASSIGNED;
|
||||
}
|
||||
|
||||
if (devinfo->smart[SMART_TEMPERATURE_CELSIUS] != SMART_UNASSIGNED)
|
||||
printf("%7" PRIu64, devinfo->smart[SMART_TEMPERATURE_CELSIUS] & mask16);
|
||||
else if (devinfo->smart[SMART_AIRFLOW_TEMPERATURE_CELSIUS] != SMART_UNASSIGNED)
|
||||
|
|
@ -932,6 +938,7 @@ void state_device(struct snapraid_state* state, int operation, tommy_list* filte
|
|||
pathcpy(entry->name, sizeof(entry->name), disk->name);
|
||||
pathcpy(entry->mount, sizeof(entry->mount), disk->dir);
|
||||
pathcpy(entry->smartctl, sizeof(entry->smartctl), disk->smartctl);
|
||||
memcpy(entry->smartignore, disk->smartignore, sizeof(entry->smartignore));
|
||||
|
||||
tommy_list_insert_tail(&high, &entry->node, entry);
|
||||
}
|
||||
|
|
@ -951,6 +958,7 @@ void state_device(struct snapraid_state* state, int operation, tommy_list* filte
|
|||
pathcpy(entry->name, sizeof(entry->name), lev_config_name(j));
|
||||
pathcpy(entry->mount, sizeof(entry->mount), state->parity[j].split_map[s].path);
|
||||
pathcpy(entry->smartctl, sizeof(entry->smartctl), state->parity[j].smartctl);
|
||||
memcpy(entry->smartignore, state->parity[j].smartignore, sizeof(entry->smartignore));
|
||||
pathcut(entry->mount); /* remove the parity file */
|
||||
|
||||
tommy_list_insert_tail(&high, &entry->node, entry);
|
||||
|
|
@ -992,7 +1000,7 @@ void state_device(struct snapraid_state* state, int operation, tommy_list* filte
|
|||
}
|
||||
|
||||
if (operation == DEVICE_SMART)
|
||||
state_smart(state->level + tommy_list_count(&state->disklist), &low);
|
||||
state_smart(state, state->level + tommy_list_count(&state->disklist), &low);
|
||||
}
|
||||
|
||||
tommy_list_foreach(&high, free);
|
||||
|
|
|
|||
|
|
@ -739,6 +739,7 @@ int dir_name_compare(const void* void_arg, const void* void_data)
|
|||
struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev, const char* uuid, int skip_access)
|
||||
{
|
||||
struct snapraid_disk* disk;
|
||||
unsigned i;
|
||||
|
||||
disk = malloc_nofail(sizeof(struct snapraid_disk));
|
||||
pathcpy(disk->name, sizeof(disk->name), name);
|
||||
|
|
@ -754,6 +755,8 @@ struct snapraid_disk* disk_alloc(const char* name, const char* dir, uint64_t dev
|
|||
#endif
|
||||
|
||||
disk->smartctl[0] = 0;
|
||||
for (i = 0; i < SMART_IGNORE_MAX; ++i)
|
||||
disk->smartignore[i] = 0;
|
||||
disk->device = dev;
|
||||
disk->tick = 0;
|
||||
disk->cached_blocks = 0;
|
||||
|
|
|
|||
|
|
@ -330,6 +330,7 @@ struct snapraid_disk {
|
|||
char name[PATH_MAX]; /**< Name of the disk. */
|
||||
char dir[PATH_MAX]; /**< Mount point of the disk. It always terminates with /. */
|
||||
char smartctl[PATH_MAX]; /**< Custom command for smartctl. Empty means auto. */
|
||||
int smartignore[SMART_IGNORE_MAX]; /**< Smart attributes to ignore for this device. */
|
||||
char uuid[UUID_MAX]; /**< UUID of the disk. */
|
||||
|
||||
uint64_t device; /**< Device identifier. */
|
||||
|
|
@ -471,6 +472,7 @@ struct snapraid_parity {
|
|||
struct snapraid_split split_map[SPLIT_MAX]; /**< Parity splits. */
|
||||
unsigned split_mac; /**< Number of parity splits. */
|
||||
char smartctl[PATH_MAX]; /**< Custom command for smartctl. Empty means auto. */
|
||||
int smartignore[SMART_IGNORE_MAX]; /**< Smart attributes to ignore for this device. */
|
||||
block_off_t total_blocks; /**< Number of total blocks. */
|
||||
block_off_t free_blocks; /**< Number of free blocks at the last sync. */
|
||||
int is_excluded_by_filter; /**< If the parity is excluded by filters. */
|
||||
|
|
|
|||
|
|
@ -2154,7 +2154,7 @@ static int devresolve(const char* mount, char* file, size_t file_size, char* wfi
|
|||
/**
|
||||
* Read a device tree filling the specified list of disk_t entries.
|
||||
*/
|
||||
static int devtree(const char* name, const char* custom, const char* wfile, devinfo_t* parent, tommy_list* list)
|
||||
static int devtree(const char* name, const char* smartctl, const int* smartignore, const char* wfile, devinfo_t* parent, tommy_list* list)
|
||||
{
|
||||
wchar_t conv_buf[CONV_MAX];
|
||||
HANDLE h;
|
||||
|
|
@ -2203,7 +2203,8 @@ static int devtree(const char* name, const char* custom, const char* wfile, devi
|
|||
devinfo = calloc_nofail(1, sizeof(devinfo_t));
|
||||
|
||||
pathcpy(devinfo->name, sizeof(devinfo->name), name);
|
||||
pathcpy(devinfo->smartctl, sizeof(devinfo->smartctl), custom);
|
||||
pathcpy(devinfo->smartctl, sizeof(devinfo->smartctl), smartctl);
|
||||
memcpy(devinfo->smartignore, smartignore, sizeof(devinfo->smartignore));
|
||||
devinfo->device = vde->Extents[i].DiskNumber;
|
||||
pathprint(devinfo->file, sizeof(devinfo->file), "/dev/pd%" PRIu64, devinfo->device);
|
||||
pathprint(devinfo->wfile, sizeof(devinfo->wfile), "\\\\.\\PhysicalDrive%" PRIu64, devinfo->device);
|
||||
|
|
@ -2339,7 +2340,7 @@ static int devscan(tommy_list* list)
|
|||
/**
|
||||
* Get SMART attributes.
|
||||
*/
|
||||
static int devsmart(uint64_t device, const char* name, const char* custom, uint64_t* smart, char* serial, char* vendor, char* model)
|
||||
static int devsmart(uint64_t device, const char* name, const char* smartctl, uint64_t* smart, char* serial, char* vendor, char* model)
|
||||
{
|
||||
char conv_buf[CONV_MAX];
|
||||
WCHAR cmd[MAX_PATH + 128];
|
||||
|
|
@ -2350,10 +2351,10 @@ static int devsmart(uint64_t device, const char* name, const char* custom, uint6
|
|||
|
||||
snprintf(file, sizeof(file), "/dev/pd%" PRIu64, device);
|
||||
|
||||
/* if there is a custom command */
|
||||
if (custom[0]) {
|
||||
/* if there is a custom smartctl command */
|
||||
if (smartctl[0]) {
|
||||
char option[128];
|
||||
snprintf(option, sizeof(option), custom, file);
|
||||
snprintf(option, sizeof(option), smartctl, file);
|
||||
snwprintf(cmd, sizeof(cmd), L"\"%lssmartctl.exe\" -a %s", exedir, option);
|
||||
} else {
|
||||
snwprintf(cmd, sizeof(cmd), L"\"%lssmartctl.exe\" -a %s", exedir, file);
|
||||
|
|
@ -2390,8 +2391,8 @@ retry:
|
|||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/* if first try without custom command */
|
||||
if (count == 0 && custom[0] == 0) {
|
||||
/* if first try without custom smartctl command */
|
||||
if (count == 0 && smartctl[0] == 0) {
|
||||
/*
|
||||
* Handle some common cases in Windows.
|
||||
*
|
||||
|
|
@ -2425,7 +2426,7 @@ retry:
|
|||
/**
|
||||
* Spin down a specific device.
|
||||
*/
|
||||
static int devdown(uint64_t device, const char* name, const char* custom)
|
||||
static int devdown(uint64_t device, const char* name, const char* smartctl)
|
||||
{
|
||||
char conv_buf[CONV_MAX];
|
||||
WCHAR cmd[MAX_PATH + 128];
|
||||
|
|
@ -2436,10 +2437,10 @@ static int devdown(uint64_t device, const char* name, const char* custom)
|
|||
|
||||
snprintf(file, sizeof(file), "/dev/pd%" PRIu64, device);
|
||||
|
||||
/* if there is a custom command */
|
||||
if (custom[0]) {
|
||||
/* if there is a custom smartctl command */
|
||||
if (smartctl[0]) {
|
||||
char option[128];
|
||||
snprintf(option, sizeof(option), custom, file);
|
||||
snprintf(option, sizeof(option), smartctl, file);
|
||||
snwprintf(cmd, sizeof(cmd), L"\"%lssmartctl.exe\" -s standby,now %s", exedir, option);
|
||||
} else {
|
||||
snwprintf(cmd, sizeof(cmd), L"\"%lssmartctl.exe\" -s standby,now %s", exedir, file);
|
||||
|
|
@ -2476,8 +2477,8 @@ retry:
|
|||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/* if first try without custom command */
|
||||
if (count == 0 && custom[0] == 0) {
|
||||
/* if first try without custom smartctl command */
|
||||
if (count == 0 && smartctl[0] == 0) {
|
||||
/*
|
||||
* Handle some common cases in Windows.
|
||||
*
|
||||
|
|
@ -2660,7 +2661,7 @@ int devquery(tommy_list* high, tommy_list* low, int operation, int others)
|
|||
}
|
||||
|
||||
/* expand the tree of devices */
|
||||
if (devtree(devinfo->name, devinfo->smartctl, devinfo->wfile, devinfo, low) != 0) {
|
||||
if (devtree(devinfo->name, devinfo->smartctl, devinfo->smartignore, devinfo->wfile, devinfo, low) != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Failed to expand device '%s'.\n", devinfo->file);
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -461,6 +461,8 @@ int randomize(void* ptr, size_t size);
|
|||
*/
|
||||
#define SMART_COUNT 260
|
||||
|
||||
#define SMART_IGNORE_MAX 4 /**< Max number of ignored smart attributes */
|
||||
|
||||
/**
|
||||
* Flags returned by smartctl.
|
||||
*/
|
||||
|
|
@ -491,6 +493,7 @@ struct devinfo_struct {
|
|||
char name[PATH_MAX]; /**< Name of the disk. */
|
||||
char mount[PATH_MAX]; /**< Mount point or other contained directory. */
|
||||
char smartctl[PATH_MAX]; /**< Options for smartctl. */
|
||||
int smartignore[SMART_IGNORE_MAX]; /**< Attribues to ignore */
|
||||
char file[PATH_MAX]; /**< File device. */
|
||||
#ifdef _WIN32
|
||||
char wfile[PATH_MAX]; /**< File device in Windows format. Like \\.\PhysicalDriveX, or \\?\Volume{X}. */
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ const char* lev_raid_name(unsigned mode, unsigned n)
|
|||
|
||||
void state_init(struct snapraid_state* state)
|
||||
{
|
||||
unsigned l, s;
|
||||
unsigned l, s, i;
|
||||
|
||||
memset(&state->opt, 0, sizeof(state->opt));
|
||||
state->filter_hidden = 0;
|
||||
|
|
@ -153,6 +153,8 @@ void state_init(struct snapraid_state* state)
|
|||
state->parity[l].split_map[s].device = 0;
|
||||
}
|
||||
state->parity[l].smartctl[0] = 0;
|
||||
for (i = 0; i < SMART_IGNORE_MAX; ++i)
|
||||
state->parity[l].smartignore[i] = 0;
|
||||
state->parity[l].total_blocks = 0;
|
||||
state->parity[l].free_blocks = 0;
|
||||
state->parity[l].skip_access = 0;
|
||||
|
|
@ -173,6 +175,8 @@ void state_init(struct snapraid_state* state)
|
|||
state->level = 1; /* default is the lowest protection */
|
||||
state->clear_past_hash = 0;
|
||||
state->no_conf = 0;
|
||||
for (i = 0; i < SMART_IGNORE_MAX; ++i)
|
||||
state->smartignore[i] = 0;
|
||||
|
||||
tommy_list_init(&state->disklist);
|
||||
tommy_list_init(&state->maplist);
|
||||
|
|
@ -1063,6 +1067,93 @@ void state_config(struct snapraid_state* state, const char* path, const char* co
|
|||
|
||||
pathcpy(disk->smartctl, sizeof(disk->smartctl), custom);
|
||||
}
|
||||
} else if (strcmp(tag, "smartignore") == 0) {
|
||||
int* smart;
|
||||
|
||||
ret = sgettok(f, buffer, sizeof(buffer));
|
||||
if (ret < 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Invalid 'smartignore' name in '%s' at line %u\n", path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (!*buffer) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Empty 'smartignore' name in '%s' at line %u\n", path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
sgetspace(f);
|
||||
|
||||
if (strcmp(buffer, "*") == 0) {
|
||||
smart = state->smartignore;
|
||||
} else if (lev_config_scan(buffer, &level, 0) == 0) { /* search for parity */
|
||||
smart = state->parity[level].smartignore;
|
||||
} else {
|
||||
struct snapraid_disk* disk;
|
||||
|
||||
/* search the disk */
|
||||
disk = 0;
|
||||
for (i = state->disklist; i != 0; i = i->next) {
|
||||
disk = i->data;
|
||||
if (strcmp(disk->name, buffer) == 0)
|
||||
break;
|
||||
}
|
||||
if (!disk) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Missing disk 'smartctl' '%s' at line %u\n", buffer, line);
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
smart = disk->smartignore;
|
||||
}
|
||||
|
||||
int si = 0;
|
||||
|
||||
while (1) {
|
||||
char* e;
|
||||
|
||||
ret = sgettok(f, buffer, sizeof(buffer));
|
||||
if (ret < 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Invalid 'smartignore' specification in '%s' at line %u\n", path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (!*buffer)
|
||||
break;
|
||||
|
||||
if (si == SMART_IGNORE_MAX) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Too many 'smartignore' specification in '%s' at line %u\n", path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
smart[si] = strtoul(buffer, &e, 0);
|
||||
|
||||
if (!e || *e) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Invalid 'smartignore' specification in '%s' at line %u\n", path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
++si;
|
||||
|
||||
sgetspace(f);
|
||||
}
|
||||
|
||||
if (si == 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Invalid 'smartignore' specification in '%s' at line %u\n", path, line);
|
||||
exit(EXIT_FAILURE);
|
||||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
} else if (strcmp(tag, "nohidden") == 0) {
|
||||
state->filter_hidden = 1;
|
||||
} else if (strcmp(tag, "exclude") == 0) {
|
||||
|
|
|
|||
|
|
@ -144,6 +144,7 @@ struct snapraid_state {
|
|||
unsigned prevhash; /**< Previous hash kind used. In case of rehash. */
|
||||
unsigned besthash; /**< Best hash suggested. */
|
||||
const char* command; /**< Command running. */
|
||||
int smartignore[SMART_IGNORE_MAX]; /**< Smart attributes to ignore for all devices. */
|
||||
tommy_list contentlist; /**< List of content files. */
|
||||
tommy_list disklist; /**< List of all the disks. */
|
||||
tommy_list maplist; /**< List of all the disk mappings. */
|
||||
|
|
|
|||
|
|
@ -513,7 +513,7 @@ static int devuuid_blkid(uint64_t device, char* uuid, size_t uuid_size)
|
|||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
static int devuuid_darwin(const char* path, char* uuid, size_t uuid_size)
|
||||
static int devuuid_darwin(const char* path, char* uuid, size_t uuid_size)
|
||||
{
|
||||
CFStringRef path_apple = CFStringCreateWithCString(kCFAllocatorDefault, path, kCFStringEncodingUTF8);
|
||||
DASessionRef session = DASessionCreate(kCFAllocatorDefault);
|
||||
|
|
@ -531,7 +531,7 @@ static int devuuid_darwin(const char* path, char* uuid, size_t uuid_size)
|
|||
path_appler = parent_path_appler;
|
||||
}
|
||||
} while (true); // This is guaranteed to succeed eventually because it'll hit `/`.
|
||||
|
||||
|
||||
CFDictionaryRef description = DADiskCopyDescription(disk);
|
||||
CFUUIDRef uuid_apple = CFDictionaryGetValue(description, kDADiskDescriptionVolumeUUIDKey);
|
||||
CFStringRef uuid_string = CFUUIDCreateString(kCFAllocatorDefault, uuid_apple);
|
||||
|
|
@ -948,7 +948,7 @@ static dev_t devread(const char* path)
|
|||
* Read a device tree filling the specified list of disk_t entries.
|
||||
*/
|
||||
#if HAVE_LINUX_DEVICE
|
||||
static int devtree(const char* name, const char* custom, dev_t device, devinfo_t* parent, tommy_list* list)
|
||||
static int devtree(const char* name, const char* smartctl, const int* smartignore, dev_t device, devinfo_t* parent, tommy_list* list)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
DIR* d;
|
||||
|
|
@ -976,7 +976,7 @@ static int devtree(const char* name, const char* custom, dev_t device, devinfo_t
|
|||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
if (devtree(name, custom, subdev, parent, list) != 0) {
|
||||
if (devtree(name, smartctl, smartignore, subdev, parent, list) != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
closedir(d);
|
||||
return -1;
|
||||
|
|
@ -1021,7 +1021,8 @@ static int devtree(const char* name, const char* custom, dev_t device, devinfo_t
|
|||
|
||||
devinfo->device = device;
|
||||
pathcpy(devinfo->name, sizeof(devinfo->name), name);
|
||||
pathcpy(devinfo->smartctl, sizeof(devinfo->smartctl), custom);
|
||||
pathcpy(devinfo->smartctl, sizeof(devinfo->smartctl), smartctl);
|
||||
memcpy(devinfo->smartignore, smartignore, sizeof(devinfo->smartignore));
|
||||
pathcpy(devinfo->file, sizeof(devinfo->file), path);
|
||||
devinfo->parent = parent;
|
||||
|
||||
|
|
@ -1118,7 +1119,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* custom, uint64_t* smart, char* serial, char* vendor, char* model)
|
||||
static int devsmart(dev_t device, const char* name, const char* smartctl, uint64_t* smart, char* serial, char* vendor, char* model)
|
||||
{
|
||||
char cmd[PATH_MAX + 64];
|
||||
char file[PATH_MAX];
|
||||
|
|
@ -1132,10 +1133,10 @@ static int devsmart(dev_t device, const char* name, const char* custom, uint64_t
|
|||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/* if there is a custom command */
|
||||
if (custom[0]) {
|
||||
/* if there is a custom smartctl command */
|
||||
if (smartctl[0]) {
|
||||
char option[PATH_MAX];
|
||||
snprintf(option, sizeof(option), custom, file);
|
||||
snprintf(option, sizeof(option), smartctl, file);
|
||||
snprintf(cmd, sizeof(cmd), "smartctl -a %s", option);
|
||||
} else {
|
||||
snprintf(cmd, sizeof(cmd), "smartctl -a %s", file);
|
||||
|
|
@ -1186,7 +1187,7 @@ static int devsmart(dev_t device, const char* name, const char* custom, uint64_t
|
|||
* Spin down a specific device.
|
||||
*/
|
||||
#if HAVE_LINUX_DEVICE
|
||||
static int devdown(dev_t device, const char* name, const char* custom)
|
||||
static int devdown(dev_t device, const char* name, const char* smartctl)
|
||||
{
|
||||
char cmd[PATH_MAX + 64];
|
||||
char file[PATH_MAX];
|
||||
|
|
@ -1200,10 +1201,10 @@ static int devdown(dev_t device, const char* name, const char* custom)
|
|||
/* LCOV_EXCL_STOP */
|
||||
}
|
||||
|
||||
/* if there is a custom command */
|
||||
if (custom[0]) {
|
||||
/* if there is a custom smartctl command */
|
||||
if (smartctl[0]) {
|
||||
char option[PATH_MAX];
|
||||
snprintf(option, sizeof(option), custom, file);
|
||||
snprintf(option, sizeof(option), smartctl, file);
|
||||
snprintf(cmd, sizeof(cmd), "smartctl -s standby,now %s", option);
|
||||
} else {
|
||||
snprintf(cmd, sizeof(cmd), "smartctl -s standby,now %s", file);
|
||||
|
|
@ -1447,7 +1448,7 @@ int devquery(tommy_list* high, tommy_list* low, int operation, int others)
|
|||
}
|
||||
|
||||
/* expand the tree of devices */
|
||||
if (devtree(devinfo->name, devinfo->smartctl, device, devinfo, low) != 0) {
|
||||
if (devtree(devinfo->name, devinfo->smartctl, devinfo->smartignore, device, devinfo, low) != 0) {
|
||||
/* LCOV_EXCL_START */
|
||||
log_fatal("Failed to expand device '%u:%u'.\n", major(device), minor(device));
|
||||
return -1;
|
||||
|
|
|
|||
26
snapraid.1
26
snapraid.1
|
|
@ -1504,6 +1504,32 @@ https://www.smartmontools.org/wiki/Supported_USB\-Devices
|
|||
.PP
|
||||
.PD
|
||||
.RE
|
||||
.SS smartignore DISK/PARITY ATTR [ATTR...]
|
||||
Ignores the specified SMART attribute when computing the probability
|
||||
of disk failure. This option is useful if a disk reports unusual or
|
||||
misleading values for a particular attribute.
|
||||
.PP
|
||||
DISK is the same disk name specified in the \[dq]disk\[dq] option.
|
||||
PARITY is one of the parity name as \[dq]parity,(1,2,3,4,5,6,z)\-parity\[dq].
|
||||
The special value * can be used to ignore the attribute on all disks.
|
||||
.PP
|
||||
For example, to ignore the \[dq]Load_Cycle_Count\[dq] attribute on all disks:
|
||||
.PP
|
||||
.RS 4
|
||||
smartignore * 193
|
||||
.PD 0
|
||||
.PP
|
||||
.PD
|
||||
.RE
|
||||
.PP
|
||||
To ignore it only on the first parity disk:
|
||||
.PP
|
||||
.RS 4
|
||||
smartignore parity 193
|
||||
.PD 0
|
||||
.PP
|
||||
.PD
|
||||
.RE
|
||||
.SS Examples
|
||||
An example of a typical configuration for Unix is:
|
||||
.PP
|
||||
|
|
|
|||
17
snapraid.d
17
snapraid.d
|
|
@ -1181,6 +1181,23 @@ Configuration
|
|||
:https://www.smartmontools.org/wiki/Supported_RAID-Controllers
|
||||
:https://www.smartmontools.org/wiki/Supported_USB-Devices
|
||||
|
||||
smartignore DISK/PARITY ATTR [ATTR...]
|
||||
Ignores the specified SMART attribute when computing the probability
|
||||
of disk failure. This option is useful if a disk reports unusual or
|
||||
misleading values for a particular attribute.
|
||||
|
||||
DISK is the same disk name specified in the "disk" option.
|
||||
PARITY is one of the parity name as "parity,(1,2,3,4,5,6,z)-parity".
|
||||
The special value * can be used to ignore the attribute on all disks.
|
||||
|
||||
For example, to ignore the "Load_Cycle_Count" attribute on all disks:
|
||||
|
||||
:smartignore * 193
|
||||
|
||||
To ignore it only on the first parity disk:
|
||||
|
||||
:smartignore parity 193
|
||||
|
||||
Examples
|
||||
An example of a typical configuration for Unix is:
|
||||
|
||||
|
|
|
|||
21
snapraid.txt
21
snapraid.txt
|
|
@ -1267,7 +1267,26 @@ Refers at the smartmontools documentation about the possible options:
|
|||
https://www.smartmontools.org/wiki/Supported_RAID-Controllers
|
||||
https://www.smartmontools.org/wiki/Supported_USB-Devices
|
||||
|
||||
7.14 Examples
|
||||
7.14 smartignore DISK/PARITY ATTR [ATTR...]
|
||||
-------------------------------------------
|
||||
|
||||
Ignores the specified SMART attribute when computing the probability
|
||||
of disk failure. This option is useful if a disk reports unusual or
|
||||
misleading values for a particular attribute.
|
||||
|
||||
DISK is the same disk name specified in the "disk" option.
|
||||
PARITY is one of the parity name as "parity,(1,2,3,4,5,6,z)-parity".
|
||||
The special value * can be used to ignore the attribute on all disks.
|
||||
|
||||
For example, to ignore the "Load_Cycle_Count" attribute on all disks:
|
||||
|
||||
smartignore * 193
|
||||
|
||||
To ignore it only on the first parity disk:
|
||||
|
||||
smartignore parity 193
|
||||
|
||||
7.15 Examples
|
||||
-------------
|
||||
|
||||
An example of a typical configuration for Unix is:
|
||||
|
|
|
|||
|
|
@ -14,4 +14,3 @@ exclude *.unrecoverable
|
|||
pool bench/pool
|
||||
share \\server\jbod
|
||||
autosave 1
|
||||
|
||||
|
|
|
|||
|
|
@ -22,4 +22,5 @@ include *.hidden
|
|||
exclude *.unrecoverable
|
||||
smartctl disk1 %s
|
||||
smartctl parity /dev/sda
|
||||
|
||||
smartignore * 193
|
||||
smartignore parity 193
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue