From 57e15416ae6aefb084e7ccdf0bad3cb248eb425a Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Mon, 28 Sep 2026 14:21:33 +0200 Subject: [PATCH] Abort spindown when filesystem flush fails --- cmdline/app.h | 3 ++- cmdline/device.c | 26 ++++++++++++++++++++++---- cmdline/mingwapp.c | 3 ++- cmdline/state.h | 5 +++++ cmdline/thermal.c | 4 ++-- cmdline/unixapp.c | 25 +++++++++++++++++++++---- 6 files changed, 54 insertions(+), 12 deletions(-) diff --git a/cmdline/app.h b/cmdline/app.h index def91c30..f53a2d74 100644 --- a/cmdline/app.h +++ b/cmdline/app.h @@ -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. diff --git a/cmdline/device.c b/cmdline/device.c index 35188293..949f43b3 100644 --- a/cmdline/device.c +++ b/cmdline/device.c @@ -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); +} + diff --git a/cmdline/mingwapp.c b/cmdline/mingwapp.c index 5873bd4a..e19cb97e 100644 --- a/cmdline/mingwapp.c +++ b/cmdline/mingwapp.c @@ -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) diff --git a/cmdline/state.h b/cmdline/state.h index 0c2ee353..993466a7 100644 --- a/cmdline/state.h +++ b/cmdline/state.h @@ -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. */ diff --git a/cmdline/thermal.c b/cmdline/thermal.c index 4e205439..821d9675 100644 --- a/cmdline/thermal.c +++ b/cmdline/thermal.c @@ -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; diff --git a/cmdline/unixapp.c b/cmdline/unixapp.c index c4124ac8..357e3f99 100644 --- a/cmdline/unixapp.c +++ b/cmdline/unixapp.c @@ -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 }