[systemd-devel] [PATCH 06/12] Support cancellation of fsck in progress
Dimitri John Ledkov
dimitri.j.ledkov at intel.com
Wed Jan 28 07:21:27 PST 2015
On 28 January 2015 at 14:53, Zbigniew Jędrzejewski-Szmek
<zbyszek at in.waw.pl> wrote:
>
> On Wed, Jan 28, 2015 at 02:22:54PM +0100, Didier Roche wrote:
> >
>
> > From 104cf82ba28941e907f277a713f834ceb3d909f0 Mon Sep 17 00:00:00 2001
> > From: Didier Roche <didrocks at ubuntu.com>
> > Date: Mon, 26 Jan 2015 16:40:52 +0100
> > Subject: [PATCH 06/12] Support cancellation of fsck in progress
> >
> > Grab in fsckd plymouth watch key for C or c, and propagate this cancel request
> > to systemd-fsck which will terminate fsck.
> Could we bind to ^c or if this is not possible, "three c's in three
> seconds" instead? I'm worried that before you could press anything to little
> effect in plymouth, and now a single key will have significant consequences.
>
Hm? an interactive message with key-binding is usually shown and then
plymouth reacts to such a key prompt.
This is how it has always worked on plymouth prompts since forever...
thus this would not be a surprise to most plymouth users (~ 5+ years
by now?!)
Doing it otherwise, will, on the contrary, impede user experience.
>
> > Send a message to signal to user what key we are grabbing for fsck cancel.
> >
> > Message is: fsckd-cancel-msg:<string>
> > Where string is a translated string ready to be displayed by the plymouth theme
> > indicating that c or C can be used to cancel current checks. It can be
> > overriden (matching only fsckd-cancel-msg prefix) for themes supporting i18n.
> > ---
> > src/fsck/fsck.c | 29 +++++++++++++++++++++--------
> > src/fsckd/fsckd.c | 43 +++++++++++++++++++++++++++++++++++++++++++
> > src/fsckd/fsckd.h | 5 +++++
> > 3 files changed, 69 insertions(+), 8 deletions(-)
> >
> > diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c
> > index f5dd546..0b42e3b 100644
> > --- a/src/fsck/fsck.c
> > +++ b/src/fsck/fsck.c
> > @@ -47,6 +47,8 @@
> > static bool arg_skip = false;
> > static bool arg_force = false;
> > static const char *arg_repair = "-a";
> > +static pid_t fsck_pid;
> > +static bool cancel_requested = false;
> >
> > static void start_target(const char *target) {
> > _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
> > @@ -165,6 +167,7 @@ static int process_progress(int fd) {
> > ssize_t n;
> > usec_t t;
> > FsckProgress progress;
> > + FsckdMessage fsckd_message;
> >
> > if (fscanf(f, "%i %lu %lu %ms", &pass, &cur, &max, &device) != 4)
> > break;
> > @@ -185,6 +188,16 @@ static int process_progress(int fd) {
> > n = send(fsckd_fd, &progress, sizeof(FsckProgress), 0);
> > if (n < 0 || (size_t) n < sizeof(FsckProgress))
> > log_warning_errno(n, "Cannot communicate fsck progress to fsckd: %m");
> > +
> > + /* get fsckd requests */
> > + n = recv(fsckd_fd, &fsckd_message, sizeof(FsckdMessage), 0);
> > + if (n > 0) {
> > + if (fsckd_message.cancel) {
> > + log_warning("Request to cancel fsck from fsckd");
> > + cancel_requested = true;
> > + kill(fsck_pid, SIGTERM);
> > + }
> > + }
> > }
> >
> > return 0;
> > @@ -193,7 +206,6 @@ static int process_progress(int fd) {
> > int main(int argc, char *argv[]) {
> > const char *cmdline[9];
> > int i = 0, r = EXIT_FAILURE, q;
> > - pid_t pid;
> > siginfo_t status;
> > _cleanup_udev_unref_ struct udev *udev = NULL;
> > _cleanup_udev_device_unref_ struct udev_device *udev_device = NULL;
> > @@ -321,11 +333,11 @@ int main(int argc, char *argv[]) {
> > cmdline[i++] = device;
> > cmdline[i++] = NULL;
> >
> > - pid = fork();
> > - if (pid < 0) {
> > + fsck_pid = fork();
> > + if (fsck_pid < 0) {
> > log_error_errno(errno, "fork(): %m");
> > goto finish;
> > - } else if (pid == 0) {
> > + } else if (fsck_pid == 0) {
> > /* Child */
> > if (progress_pipe[0] >= 0)
> > safe_close(progress_pipe[0]);
> > @@ -340,7 +352,7 @@ int main(int argc, char *argv[]) {
> > progress_pipe[0] = -1;
> > }
> >
> > - q = wait_for_terminate(pid, &status);
> > + q = wait_for_terminate(fsck_pid, &status);
> > if (q < 0) {
> > log_error_errno(q, "waitid(): %m");
> > goto finish;
> > @@ -348,11 +360,11 @@ int main(int argc, char *argv[]) {
> >
> > if (status.si_code != CLD_EXITED || (status.si_status & ~1)) {
> >
> > - if (status.si_code == CLD_KILLED || status.si_code == CLD_DUMPED)
> > + if ((!cancel_requested && status.si_code == CLD_KILLED) || status.si_code == CLD_DUMPED)
> > log_error("fsck terminated by signal %s.", signal_to_string(status.si_status));
> > else if (status.si_code == CLD_EXITED)
> > log_error("fsck failed with error code %i.", status.si_status);
> > - else
> > + else if (!cancel_requested)
> > log_error("fsck failed due to unknown reason.");
> >
> > if (status.si_code == CLD_EXITED && (status.si_status & 2) && root_directory)
> > @@ -363,7 +375,8 @@ int main(int argc, char *argv[]) {
> > start_target(SPECIAL_EMERGENCY_TARGET);
> > else {
> > r = EXIT_SUCCESS;
> > - log_warning("Ignoring error.");
> > + if (!cancel_requested)
> > + log_warning("Ignoring error.");
> > }
> >
> > } else
> > diff --git a/src/fsckd/fsckd.c b/src/fsckd/fsckd.c
> > index b516193..5760916 100644
> > --- a/src/fsckd/fsckd.c
> > +++ b/src/fsckd/fsckd.c
> > @@ -57,10 +57,15 @@ typedef struct Clients {
> > unsigned long max;
> > int pass;
> > double percent;
> > + bool cancelled;
> >
> > LIST_FIELDS(struct Clients, clients);
> > } Clients;
> >
> > +#ifdef HAVE_PLYMOUTH
> > +static bool cancelled = false;
> > +#endif
> > +
> > static double compute_percent(int pass, unsigned long cur, unsigned long max) {
> > /* Values stolen from e2fsck */
> >
> > @@ -79,12 +84,25 @@ static double compute_percent(int pass, unsigned long cur, unsigned long max) {
> > (double) cur / (double) max;
> > }
> >
> > +#ifdef HAVE_PLYMOUTH
> > +static void cancel_requested(void) {
> > + log_debug("Request to cancel fsck checking received");
> > + cancelled = true;
> > +}
> > +#endif
> > +
> > static int handle_requests(int socket_fd) {
> > Clients *first = NULL;
> > usec_t last_activity = 0;
> > int numdevices = 0, clear = 0;
> > double percent = 100;
> > _cleanup_fclose_ FILE *console = NULL;
> > +#ifdef HAVE_PLYMOUTH
> > + const char *plymouth_cancel_message;
> > + bool cancel_message_plymouth_sent = false;
> > +
> > + plymouth_cancel_message = strappenda("fsckd-cancel-msg:", "Press C to cancel all checks in progress");
> > +#endif
> >
> > console = fopen("/dev/console", "we");
> > if (!console) {
> > @@ -111,6 +129,7 @@ static int handle_requests(int socket_fd) {
> > log_debug("new fsck client connected to fd: %d", new_client_fd);
> > current = alloca0(sizeof(Clients));
> > current->fd = new_client_fd;
> > + current->cancelled = false;
> > if (!first)
> > LIST_INIT(clients, current);
> > else
> > @@ -143,6 +162,20 @@ static int handle_requests(int socket_fd) {
> >
> > log_debug("Getting progress for %s: (%lu, %lu, %d) : %3.1f%%",
> > current->device, current->cur, current->max, current->pass, current->percent);
> > +
> > +#ifdef HAVE_PLYMOUTH
> > + /* send cancel message if cancel key was pressed (and the socket wasn't closed) */
> > + if (cancelled && !current->cancelled) {
> > + FsckdMessage cancel_msg;
> > + ssize_t n;
> > + cancel_msg.cancel = true;
> > + n = send(current->fd, &cancel_msg, sizeof(FsckdMessage), 0);
> > + if (n < 0 || (size_t) n < sizeof(FsckdMessage))
> > + log_warning_errno(n, "Cannot send cancel to fsck on %s: %m", current->device);
> > + else
> > + current->cancelled = true;
> > + }
> > +#endif
> > }
> >
> > /* update global (eventually cached) values. */
> > @@ -173,6 +206,10 @@ static int handle_requests(int socket_fd) {
> >
> > #ifdef HAVE_PLYMOUTH
> > /* send to plymouth */
> > + if (!cancel_message_plymouth_sent) {
> > + cancel_message_plymouth_sent = \
> > + plymouth_watch_key("Cc", plymouth_cancel_message, cancel_requested);
> > + }
> > plymouth_update(fsck_message);
> > #endif
> >
> > @@ -183,6 +220,12 @@ static int handle_requests(int socket_fd) {
> > /* idle out after IDLE_TIME_MINUTES minutes with no connected device */
> > t = now(CLOCK_MONOTONIC);
> > if (numdevices == 0) {
> > +#ifdef HAVE_PLYMOUTH
> > + if (cancel_message_plymouth_sent) {
> > + plymouth_delete_message();
> > + cancel_message_plymouth_sent = false;
> > + }
> > +#endif
> > if (t > last_activity + IDLE_TIME_MINUTES * USEC_PER_MINUTE) {
> > log_debug("No fsck in progress for the last %d minutes, shutting down.", IDLE_TIME_MINUTES);
> > break;
> > diff --git a/src/fsckd/fsckd.h b/src/fsckd/fsckd.h
> > index e8cd014..6a029ec 100644
> > --- a/src/fsckd/fsckd.h
> > +++ b/src/fsckd/fsckd.h
> > @@ -23,6 +23,7 @@
> > ***/
> >
> > #include <linux/limits.h>
> > +#include <stdbool.h>
> >
> > #define FSCKD_SOCKET_PATH "/run/systemd/fsckd"
> >
> > @@ -32,3 +33,7 @@ typedef struct FsckProgress {
> > int pass;
> > char device[PATH_MAX];
> > } FsckProgress;
> > +
> > +typedef struct FsckdMessage {
> > + bool cancel;
> > +} FsckdMessage;
>
> Zbyszek
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
Regards,
Dimitri.
Intel Corporation (UK) Ltd. - Co. Reg. #1134945 - Pipers Way, Swindon SN3 1RJ.
More information about the systemd-devel
mailing list