diff options
author | Lennart Poettering <lennart@poettering.net> | 2010-09-26 15:50:14 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2010-09-26 15:50:14 +0200 |
commit | 6624768c9c39ab409edebe07cb06ecd93cc6f3ed (patch) | |
tree | 977498358b71fcf0bd9c3f8623e9c42d58d72d72 /src | |
parent | f0cf061eda90f60730dbb222675e48d11e8cf757 (diff) |
readahead: add interface to sd-daemon.[ch] to control readahead
Diffstat (limited to 'src')
-rw-r--r-- | src/notify.c | 42 | ||||
-rw-r--r-- | src/readahead-collect.c | 73 | ||||
-rw-r--r-- | src/readahead-common.c | 21 | ||||
-rw-r--r-- | src/readahead-common.h | 2 | ||||
-rw-r--r-- | src/readahead-replay.c | 43 | ||||
-rw-r--r-- | src/sd-daemon.c | 38 | ||||
-rw-r--r-- | src/sd-daemon.h | 10 |
7 files changed, 211 insertions, 18 deletions
diff --git a/src/notify.c b/src/notify.c index 28cfe23b23..61c4b0f92f 100644 --- a/src/notify.c +++ b/src/notify.c @@ -36,16 +36,18 @@ static bool arg_ready = false; static pid_t arg_pid = 0; static const char *arg_status = NULL; static bool arg_booted = false; +static const char *arg_readahead = NULL; static int help(void) { printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n\n" "Notify the init system about service status updates.\n\n" - " -h --help Show this help\n" - " --ready Inform the init system about service start-up completion\n" - " --pid[=PID] Set main pid of daemon\n" - " --status=TEXT Set status text\n" - " --booted Returns 0 if the system was booted up with systemd, non-zero otherwise\n", + " -h --help Show this help\n" + " --ready Inform the init system about service start-up completion\n" + " --pid[=PID] Set main pid of daemon\n" + " --status=TEXT Set status text\n" + " --booted Returns 0 if the system was booted up with systemd, non-zero otherwise\n" + " --readahead=ACTION Controls read-ahead operations\n", program_invocation_short_name); return 0; @@ -57,16 +59,18 @@ static int parse_argv(int argc, char *argv[]) { ARG_READY = 0x100, ARG_PID, ARG_STATUS, - ARG_BOOTED + ARG_BOOTED, + ARG_READAHEAD }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "ready", no_argument, NULL, ARG_READY }, - { "pid", optional_argument, NULL, ARG_PID }, - { "status", required_argument, NULL, ARG_STATUS }, - { "booted", no_argument, NULL, ARG_BOOTED }, - { NULL, 0, NULL, 0 } + { "help", no_argument, NULL, 'h' }, + { "ready", no_argument, NULL, ARG_READY }, + { "pid", optional_argument, NULL, ARG_PID }, + { "status", required_argument, NULL, ARG_STATUS }, + { "booted", no_argument, NULL, ARG_BOOTED }, + { "readahead", required_argument, NULL, ARG_READAHEAD }, + { NULL, 0, NULL, 0 } }; int c; @@ -106,6 +110,10 @@ static int parse_argv(int argc, char *argv[]) { arg_booted = true; break; + case ARG_READAHEAD: + arg_readahead = optarg; + break; + case '?': return -EINVAL; @@ -119,7 +127,8 @@ static int parse_argv(int argc, char *argv[]) { !arg_ready && !arg_status && !arg_pid && - !arg_booted) { + !arg_booted && + !arg_readahead) { help(); return -EINVAL; } @@ -144,6 +153,13 @@ int main(int argc, char* argv[]) { if (arg_booted) return sd_booted() <= 0; + if (arg_readahead) { + if ((r = sd_readahead(arg_readahead)) < 0) { + log_error("Failed to issue read-ahead control command: %s", strerror(-r)); + goto finish; + } + } + if (arg_ready) our_env[i++] = (char*) "READY=1"; diff --git a/src/readahead-collect.c b/src/readahead-collect.c index 817b958f61..aa136ce50e 100644 --- a/src/readahead-collect.c +++ b/src/readahead-collect.c @@ -41,6 +41,7 @@ #include <sys/ioctl.h> #include <sys/vfs.h> #include <getopt.h> +#include <sys/inotify.h> #include "missing.h" #include "util.h" @@ -56,6 +57,7 @@ * - sd_readahead_cancel * - gzip? * - remount rw? + * - handle files where nothing is in mincore * - does ioprio_set work with fadvise()? */ @@ -199,12 +201,13 @@ static int qsort_compare(const void *a, const void *b) { static int collect(const char *root) { enum { - FD_FANOTIFY, + FD_FANOTIFY, /* Get the actualy fs events */ FD_SIGNAL, + FD_INOTIFY, /* We get notifications to quit early via this fd */ _FD_MAX }; struct pollfd pollfd[_FD_MAX]; - int fanotify_fd = -1, signal_fd = -1, r = 0; + int fanotify_fd = -1, signal_fd = -1, inotify_fd = -1, r = 0; pid_t my_pid; Hashmap *files = NULL; Iterator i; @@ -251,6 +254,11 @@ static int collect(const char *root) { goto finish; } + if ((inotify_fd = open_inotify()) < 0) { + r = inotify_fd; + goto finish; + } + not_after = now(CLOCK_MONOTONIC) + arg_timeout; my_pid = getpid(); @@ -260,6 +268,8 @@ static int collect(const char *root) { pollfd[FD_FANOTIFY].events = POLLIN; pollfd[FD_SIGNAL].fd = signal_fd; pollfd[FD_SIGNAL].events = POLLIN; + pollfd[FD_INOTIFY].fd = inotify_fd; + pollfd[FD_INOTIFY].events = POLLIN; sd_notify(0, "READY=1\n" @@ -267,6 +277,17 @@ static int collect(const char *root) { log_debug("Collecting..."); + if (access("/dev/.systemd/readahead/cancel", F_OK) >= 0) { + log_debug("Collection canceled"); + r = -ECANCELED; + goto finish; + } + + if (access("/dev/.systemd/readahead/done", F_OK) >= 0) { + log_debug("Got termination request"); + goto done; + } + for (;;) { union { struct fanotify_event_metadata metadata; @@ -298,14 +319,52 @@ static int collect(const char *root) { goto finish; } - if (pollfd[FD_SIGNAL].revents != 0) - break; - if (h == 0) { log_debug("Reached maximum collection time, ending collection."); break; } + if (pollfd[FD_SIGNAL].revents) { + log_debug("Got signal."); + break; + } + + if (pollfd[FD_INOTIFY].revents) { + uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; + struct inotify_event *e; + + if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + + log_error("Failed to read inotify event: %m"); + r = -errno; + goto finish; + } + + e = (struct inotify_event*) inotify_buffer; + while (n > 0) { + size_t step; + + if ((e->mask & IN_CREATE) && streq(e->name, "cancel")) { + log_debug("Collection canceled"); + r = -ECANCELED; + goto finish; + } + + if ((e->mask & IN_CREATE) && streq(e->name, "done")) { + log_debug("Got termination request"); + goto done; + } + + step = sizeof(struct inotify_event) + e->len; + assert(step <= (size_t) n); + + e = (struct inotify_event*) ((uint8_t*) e + step); + n -= step; + } + } + if ((n = read(fanotify_fd, &data, sizeof(data))) < 0) { if (errno == EINTR || errno == EAGAIN) @@ -352,6 +411,7 @@ static int collect(const char *root) { } } +done: if (fanotify_fd >= 0) { close_nointr_nofail(fanotify_fd); fanotify_fd = -1; @@ -451,6 +511,9 @@ finish: if (signal_fd >= 0) close_nointr_nofail(signal_fd); + if (inotify_fd >= 0) + close_nointr_nofail(inotify_fd); + if (pack) { fclose(pack); unlink(pack_fn_new); diff --git a/src/readahead-common.c b/src/readahead-common.c index a1016a3ede..a2f6f173e9 100644 --- a/src/readahead-common.c +++ b/src/readahead-common.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include <string.h> #include <sys/sysinfo.h> +#include <sys/inotify.h> #include "log.h" #include "readahead-common.h" @@ -116,3 +117,23 @@ bool enough_ram(void) { * with at least 128MB * memory */ } + +int open_inotify(void) { + int fd; + + if ((fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) { + log_error("Failed to create inotify handle: %m"); + return -errno; + } + + mkdir("/dev/.systemd", 0755); + mkdir("/dev/.systemd/readahead", 0755); + + if (inotify_add_watch(fd, "/dev/.systemd/readahead", IN_CREATE) < 0) { + log_error("Failed to watch /dev/.systemd/readahead: %m"); + close_nointr_nofail(fd); + return -errno; + } + + return fd; +} diff --git a/src/readahead-common.h b/src/readahead-common.h index c7fd713e13..3f64f290a9 100644 --- a/src/readahead-common.h +++ b/src/readahead-common.h @@ -32,4 +32,6 @@ int fs_on_ssd(const char *p); bool enough_ram(void); +int open_inotify(void); + #endif diff --git a/src/readahead-replay.c b/src/readahead-replay.c index d4ddf26aac..a5a2936b3e 100644 --- a/src/readahead-replay.c +++ b/src/readahead-replay.c @@ -33,6 +33,7 @@ #include <sys/stat.h> #include <unistd.h> #include <getopt.h> +#include <sys/inotify.h> #include "missing.h" #include "util.h" @@ -119,6 +120,7 @@ static int replay(const char *root) { char *pack_fn = NULL, c; bool on_ssd, ready = false; int prio; + int inotify_fd = -1; assert(root); @@ -141,6 +143,11 @@ static int replay(const char *root) { goto finish; } + if ((inotify_fd = open_inotify()) < 0) { + r = inotify_fd; + goto finish; + } + if (!(fgets(line, sizeof(line), pack))) { log_error("Premature end of pack file."); r = -EIO; @@ -177,8 +184,40 @@ static int replay(const char *root) { log_debug("Replaying..."); + if (access("/dev/.systemd/readahead/noreplay", F_OK) >= 0) { + log_debug("Got termination request"); + goto done; + } + while (!feof(pack) && !ferror(pack)) { + uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; int k; + ssize_t n; + + if ((n = read(inotify_fd, &inotify_buffer, sizeof(inotify_buffer))) < 0) { + if (errno != EINTR && errno != EAGAIN) { + log_error("Failed to read inotify event: %m"); + r = -errno; + goto finish; + } + } else { + struct inotify_event *e = (struct inotify_event*) inotify_buffer; + + while (n > 0) { + size_t step; + + if ((e->mask & IN_CREATE) && streq(e->name, "noreplay")) { + log_debug("Got termination request"); + goto done; + } + + step = sizeof(struct inotify_event) + e->len; + assert(step <= (size_t) n); + + e = (struct inotify_event*) ((uint8_t*) e + step); + n -= step; + } + } if ((k = unpack_file(pack)) < 0) { r = k; @@ -193,6 +232,7 @@ static int replay(const char *root) { } } +done: if (!ready) sd_notify(0, "READY=1"); @@ -208,6 +248,9 @@ finish: if (pack) fclose(pack); + if (inotify_fd >= 0) + close_nointr_nofail(inotify_fd); + free(pack_fn); return r; diff --git a/src/sd-daemon.c b/src/sd-daemon.c index 9c23b917f9..316fccc50a 100644 --- a/src/sd-daemon.c +++ b/src/sd-daemon.c @@ -433,3 +433,41 @@ int sd_booted(void) { return a.st_dev != b.st_dev; #endif } + +static int touch(const char *path) { + +#if !defined(DISABLE_SYSTEMD) && defined(__linux__) + int fd; + + mkdir("/dev/.systemd", 0755); + mkdir("/dev/.systemd/readahead", 0755); + + if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0666)) < 0) + return -errno; + + for (;;) { + if (close(fd) >= 0) + break; + + if (errno != -EINTR) + return -errno; + } + +#endif + return 0; +} + +int sd_readahead(const char *action) { + + if (!action) + return -EINVAL; + + if (strcmp(action, "cancel") == 0) + return touch("/dev/.systemd/readahead/cancel"); + else if (strcmp(action, "done") == 0) + return touch("/dev/.systemd/readahead/done"); + else if (strcmp(action, "noreplay") == 0) + return touch("/dev/.systemd/readahead/noreplay"); + + return -EINVAL; +} diff --git a/src/sd-daemon.h b/src/sd-daemon.h index 008a44c1d2..2fbfe955ce 100644 --- a/src/sd-daemon.h +++ b/src/sd-daemon.h @@ -254,6 +254,16 @@ int sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_attr_( */ int sd_booted(void) _sd_hidden_; +/* + Controls ongoing disk read-ahead operations during boot-up. The argument + must be a string, and either "cancel", "done" or "noreplay". + + cancel = terminate read-ahead data collection, drop collected information + done = terminate read-ahead data collection, keep collected information + noreplay = terminate read-ahead replay +*/ +int sd_readahead(const char *action); + #ifdef __cplusplus } #endif |