chiark / gitweb /
readahead-replay: use posix_fadvise instead of readahead
[elogind.git] / src / readahead-replay.c
index d4ddf26aac4f41106e6343086a606a272fdc6fbe..32941c144d5553dddcda4ca6dc7e88f04caf50b0 100644 (file)
@@ -33,6 +33,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <getopt.h>
+#include <sys/inotify.h>
 
 #include "missing.h"
 #include "util.h"
@@ -88,8 +89,8 @@ static int unpack_file(FILE *pack) {
                 any = true;
 
                 if (fd >= 0)
-                        if (readahead(fd, b * PAGE_SIZE, (c - b) * PAGE_SIZE) < 0) {
-                                log_warning("readahead() failed: %m");
+                        if (posix_fadvise(fd, b * PAGE_SIZE, (c - b) * PAGE_SIZE, POSIX_FADV_WILLNEED) < 0) {
+                                log_warning("posix_fadvise() failed: %m");
                                 goto finish;
                         }
         }
@@ -99,8 +100,8 @@ static int unpack_file(FILE *pack) {
                  * intended to mean that the whole file shall be
                  * read */
 
-                if (readahead(fd, 0, st.st_size) < 0) {
-                        log_warning("readahead() failed: %m");
+                if (posix_fadvise(fd, 0, st.st_size, POSIX_FADV_WILLNEED) < 0) {
+                        log_warning("posix_fadvise() failed: %m");
                         goto finish;
                 }
         }
@@ -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;