chiark / gitweb /
tmpfiles: separate a generic item glob processing function
[elogind.git] / src / readahead-collect.c
index 0838dd392919887e5aee6c40ebf21b6f69bc560c..eac11e7e5c160477f6c8ba61fd4d2394a67b6b97 100644 (file)
@@ -49,6 +49,7 @@
 #include "sd-daemon.h"
 #include "ioprio.h"
 #include "readahead-common.h"
+#include "virt.h"
 
 /* fixme:
  *
@@ -64,6 +65,8 @@ static unsigned arg_files_max = 16*1024;
 static off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX;
 static usec_t arg_timeout = 2*USEC_PER_MINUTE;
 
+static ReadaheadShared *shared = NULL;
+
 /* Avoid collisions with the NULL pointer */
 #define SECTOR_TO_PTR(s) ULONG_TO_PTR((s)+1)
 #define PTR_TO_SECTOR(p) (PTR_TO_ULONG(p)-1)
@@ -90,6 +93,13 @@ static int pack_file(FILE *pack, const char *fn, bool on_btrfs) {
         assert(fn);
 
         if ((fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW)) < 0) {
+
+                if (errno == ENOENT)
+                        return 0;
+
+                if (errno == EPERM || errno == EACCES)
+                        return 0;
+
                 log_warning("open(%s) failed: %m", fn);
                 r = -errno;
                 goto finish;
@@ -110,9 +120,10 @@ static int pack_file(FILE *pack, const char *fn, bool on_btrfs) {
                 goto finish;
         }
 
-        pages = l / PAGE_SIZE;
+        pages = l / page_size();
 
         vec = alloca(pages);
+        memset(vec, 0, pages);
         if (mincore(start, l, vec) < 0) {
                 log_warning("mincore(%s) failed: %m", fn);
                 r = -errno;
@@ -280,13 +291,13 @@ static int collect(const char *root) {
 
         log_debug("Collecting...");
 
-        if (access("/dev/.systemd/readahead/cancel", F_OK) >= 0) {
+        if (access("/run/systemd/readahead/cancel", F_OK) >= 0) {
                 log_debug("Collection canceled");
                 r = -ECANCELED;
                 goto finish;
         }
 
-        if (access("/dev/.systemd/readahead/done", F_OK) >= 0) {
+        if (access("/run/systemd/readahead/done", F_OK) >= 0) {
                 log_debug("Got termination request");
                 goto done;
         }
@@ -373,42 +384,60 @@ static int collect(const char *root) {
                         if (errno == EINTR || errno == EAGAIN)
                                 continue;
 
+                        /* fanotify sometimes returns EACCES on read()
+                         * where it shouldn't. For now let's just
+                         * ignore it here (which is safe), but
+                         * eventually this should be
+                         * dropped when the kernel is fixed.
+                         *
+                         * https://bugzilla.redhat.com/show_bug.cgi?id=707577 */
+                        if (errno == EACCES)
+                                continue;
+
                         log_error("Failed to read event: %m");
                         r = -errno;
                         goto finish;
                 }
 
                 for (m = &data.metadata; FAN_EVENT_OK(m, n); m = FAN_EVENT_NEXT(m, n)) {
+                        char fn[PATH_MAX];
+                        int k;
 
-                        if (m->pid != my_pid && m->fd >= 0) {
-                                char fn[PATH_MAX];
-                                int k;
+                        if (m->fd < 0)
+                                goto next_iteration;
 
-                                snprintf(fn, sizeof(fn), "/proc/self/fd/%i", m->fd);
-                                char_array_0(fn);
+                        if (m->pid == my_pid)
+                                goto next_iteration;
 
-                                if ((k = readlink_malloc(fn, &p)) >= 0) {
+                        __sync_synchronize();
+                        if (m->pid == shared->replay)
+                                goto next_iteration;
 
-                                        if (startswith(p, "/tmp") ||
-                                            hashmap_get(files, p))
-                                                /* Not interesting, or
-                                                 * already read */
-                                                free(p);
-                                        else {
-                                                unsigned long ul;
+                        snprintf(fn, sizeof(fn), "/proc/self/fd/%i", m->fd);
+                        char_array_0(fn);
 
-                                                ul = fd_first_block(m->fd);
+                        if ((k = readlink_malloc(fn, &p)) >= 0) {
+                                if (startswith(p, "/tmp") ||
+                                    endswith(p, " (deleted)") ||
+                                    hashmap_get(files, p))
+                                        /* Not interesting, or
+                                         * already read */
+                                        free(p);
+                                else {
+                                        unsigned long ul;
 
-                                                if ((k = hashmap_put(files, p, SECTOR_TO_PTR(ul))) < 0) {
-                                                        log_warning("set_put() failed: %s", strerror(-k));
-                                                        free(p);
-                                                }
+                                        ul = fd_first_block(m->fd);
+
+                                        if ((k = hashmap_put(files, p, SECTOR_TO_PTR(ul))) < 0) {
+                                                log_warning("set_put() failed: %s", strerror(-k));
+                                                free(p);
                                         }
+                                }
 
-                                } else
-                                        log_warning("readlink(%s) failed: %s", fn, strerror(-k));
-                        }
+                        } else
+                                log_warning("readlink(%s) failed: %s", fn, strerror(-k));
 
+                next_iteration:
                         if (m->fd)
                                 close_nointr_nofail(m->fd);
                 }
@@ -425,7 +454,7 @@ done:
         on_ssd = fs_on_ssd(root) > 0;
         log_debug("On SSD: %s", yes_no(on_ssd));
 
-        on_btrfs = statfs(root, &sfs) >= 0 && sfs.f_type == BTRFS_SUPER_MAGIC;
+        on_btrfs = statfs(root, &sfs) >= 0 && (long) sfs.f_type == (long) BTRFS_SUPER_MAGIC;
         log_debug("On btrfs: %s", yes_no(on_btrfs));
 
         asprintf(&pack_fn, "%s/.readahead", root);
@@ -622,20 +651,41 @@ static int parse_argv(int argc, char *argv[]) {
 
 int main(int argc, char *argv[]) {
         int r;
+        const char *root;
 
         log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
         log_parse_environment();
         log_open();
 
+        umask(0022);
+
         if ((r = parse_argv(argc, argv)) <= 0)
                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
 
+        root = optind < argc ? argv[optind] : "/";
+
+        if (fs_on_read_only(root) > 0) {
+                log_info("Disabling readahead collector due to read-only media.");
+                return 0;
+        }
+
         if (!enough_ram()) {
                 log_info("Disabling readahead collector due to low memory.");
                 return 0;
         }
 
-        if (collect(optind < argc ? argv[optind] : "/") < 0)
+        if (detect_virtualization(NULL) > 0) {
+                log_info("Disabling readahead collector due to execution in virtualized environment.");
+                return 0;
+        }
+
+        if (!(shared = shared_get()))
+                return 1;
+
+        shared->collect = getpid();
+        __sync_synchronize();
+
+        if (collect(root) < 0)
                 return 1;
 
         return 0;