[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