Abort spindown when filesystem flush fails

This commit is contained in:
Andrea Mazzoleni 2026-09-28 14:21:33 +02:00
parent d210e95997
commit 57e15416ae
6 changed files with 54 additions and 12 deletions

View file

@ -422,8 +422,9 @@ void device_name_set(devinfo_t* dev, const char* name, int index);
/**
* Sync filesystems associated with the "high" level devices.
* Return 0 on success, -1 on error.
*/
void devsync(tommy_list* high);
int devsync(tommy_list* high);
/**
* Query all the "high" level devices and produce a list of "low" level devices.

View file

@ -1090,13 +1090,14 @@ void state_devmap(struct snapraid_state* state)
}
}
int state_device(struct snapraid_state* state, int operation, tommy_list* filterlist_disk)
int state_device_force(struct snapraid_state* state, int operation, tommy_list* filterlist_disk, int force)
{
tommy_node* i;
unsigned j;
tommy_list high;
tommy_list low;
int ret;
int sync_failed = 0;
time_t now = time(0);
switch (operation) {
@ -1192,9 +1193,19 @@ int state_device(struct snapraid_state* state, int operation, tommy_list* filter
if (state->opt.fake_device) {
ret = devtest(&high, &low, operation);
} else {
/* issue pending filesystem writes before the underlying devices enter standby */
if (operation == DEVICE_DOWN)
devsync(&high);
/*
* Flush before DOWN, but not DOWNIFUP: syncfs() could wake disks
* already in standby during the repeated thermal cooldown checks.
*/
if (operation == DEVICE_DOWN) {
ret = devsync(&high);
if (ret != 0) {
/* thermal cooldown must attempt spindown even after a failed flush */
if (!force)
goto bail;
sync_failed = 1;
}
}
ret = devquery(&high, &low);
if (ret > 0) {
@ -1254,7 +1265,14 @@ bail:
ret = 1;
if (ret == 0 && query_failed)
ret = -1;
if (sync_failed)
ret = -1;
return ret;
}
int state_device(struct snapraid_state* state, int operation, tommy_list* filterlist_disk)
{
return state_device_force(state, operation, filterlist_disk, 0);
}

View file

@ -2178,9 +2178,10 @@ static int device_thread(tommy_list* list, void* (*func)(void* arg))
return 0;
}
void devsync(tommy_list* high)
int devsync(tommy_list* high)
{
(void)high;
return 0;
}
int devquery(tommy_list* high, tommy_list* low)

View file

@ -275,6 +275,11 @@ void state_devmap(struct snapraid_state* state);
*/
int state_device(struct snapraid_state* state, int operation, tommy_list* filterlist_disk);
/**
* Perform a device operation, continuing after a failed flush when force is set.
*/
int state_device_force(struct snapraid_state* state, int operation, tommy_list* filterlist_disk, int force);
/**
* Sync the parity data.
*/

View file

@ -365,7 +365,7 @@ void state_thermal_cooldown(struct snapraid_state* state)
* effective; it does not allow the operation to resume while a measurable disk
* is still above the temperature limit.
*/
state_device(state, DEVICE_DOWN, 0);
state_device_force(state, DEVICE_DOWN, 0, 1);
msg_progress("Cooldown...\n");
@ -376,7 +376,7 @@ void state_thermal_cooldown(struct snapraid_state* state)
/* every 30 seconds spin down any disk that was spunup */
while (sleep_time > 0 && !os_signal_interrupt()) {
state_device(state, DEVICE_DOWNIFUP, 0);
state_device_force(state, DEVICE_DOWNIFUP, 0, 1);
sleep(30);
sleep_time -= 30;

View file

@ -4265,11 +4265,13 @@ static int device_thread(tommy_list* list, void* (*func)(void* arg))
return 0;
}
void devsync(tommy_list* high)
int devsync(tommy_list* high)
{
#if HAVE_SYNCFS
tommy_node* i;
int ret = 0;
/* flush every filesystem even if one fails before a forced thermal spindown */
for (i = tommy_list_head(high); i != 0; i = i->next) {
devinfo_t* devinfo = i->data;
int f;
@ -4279,13 +4281,28 @@ void devsync(tommy_list* high)
continue;
f = open(devinfo->mount, O_RDONLY);
if (f >= 0) {
syncfs(f);
close(f);
if (f < 0) {
log_error(errno, "Failed to open filesystem at '%s'. %s.\n", devinfo->mount, strerror(errno));
ret = -1;
continue;
}
if (syncfs(f) != 0) {
int err = errno;
log_error(err, "Failed to sync filesystem at '%s'. %s.\n", devinfo->mount, strerror(err));
ret = -1;
}
if (close(f) != 0) {
log_error(errno, "Failed to close filesystem at '%s'. %s.\n", devinfo->mount, strerror(errno));
ret = -1;
}
}
return ret;
#else
(void)high;
return 0;
#endif
}