[systemd-commits] 2 commits - TODO src/readahead src/shared

Lennart Poettering lennart at kemper.freedesktop.org
Thu May 3 15:14:46 PDT 2012


 TODO                              |    2 
 src/readahead/readahead-collect.c |   33 ++++++++++++---
 src/readahead/readahead-common.c  |   82 +++++++++++++++++++++++++++++++++++++-
 src/readahead/readahead-common.h  |    5 +-
 src/readahead/readahead-replay.c  |    2 
 src/shared/cgroup-util.c          |   33 +++++++++++----
 6 files changed, 138 insertions(+), 19 deletions(-)

New commits:
commit 6de338a2d9904ef5a67552b024491700523074a3
Author: Lennart Poettering <lennart at poettering.net>
Date:   Fri May 4 00:13:20 2012 +0200

    readhead: temporarily lower the kernel's read_ahead_kb setting while collecting
    
    While collecting readahead data we want to know exactly what userspace
    accesses unblurred by the kernel's read_ahead_kb. Hence lower this
    during collection, and raise it afterwards.
    
    This is mostly based on ideas and code by Auke Kok.

diff --git a/src/readahead/readahead-collect.c b/src/readahead/readahead-collect.c
index 008ede3..70e0f66 100644
--- a/src/readahead/readahead-collect.c
+++ b/src/readahead/readahead-collect.c
@@ -233,9 +233,26 @@ static int collect(const char *root) {
         bool on_ssd, on_btrfs;
         struct statfs sfs;
         usec_t not_after;
+        uint64_t previous_block_readahead;
+        bool previous_block_readahead_set = false;
 
         assert(root);
 
+        if (asprintf(&pack_fn, "%s/.readahead", root) < 0) {
+                log_error("Out of memory");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        /* If there's no pack file yet we lower the kernel readahead
+         * so that mincore() is accurate. If there is a pack file
+         * already we assume it is accurate enough so that kernel
+         * readahead is never triggered. */
+        previous_block_readahead_set =
+                access(pack_fn, F_OK) < 0 &&
+                block_get_readahead(root, &previous_block_readahead) >= 0 &&
+                block_set_readahead(root, 8*1024) >= 0;
+
         write_one_line_file("/proc/self/oom_score_adj", "1000");
 
         if (ioprio_set(IOPRIO_WHO_PROCESS, getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)) < 0)
@@ -458,10 +475,7 @@ done:
         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);
-        asprintf(&pack_fn_new, "%s/.readahead.new", root);
-
-        if (!pack_fn || !pack_fn_new) {
+        if (asprintf(&pack_fn_new, "%s/.readahead.new", root) < 0) {
                 log_error("Out of memory");
                 r = -ENOMEM;
                 goto finish;
@@ -551,7 +565,6 @@ finish:
                 fclose(pack);
                 unlink(pack_fn_new);
         }
-
         free(pack_fn_new);
         free(pack_fn);
 
@@ -560,6 +573,16 @@ finish:
 
         hashmap_free(files);
 
+        if (previous_block_readahead_set) {
+                uint64_t bytes;
+
+                /* Restore the original kernel readahead setting if we
+                 * changed it, and nobody has overwritten it since
+                 * yet. */
+                if (block_get_readahead(root, &bytes) >= 0 && bytes == 8*1024)
+                        block_set_readahead(root, previous_block_readahead);
+        }
+
         return r;
 }
 
diff --git a/src/readahead/readahead-common.c b/src/readahead/readahead-common.c
index 4e8e636..99dbac2 100644
--- a/src/readahead/readahead-common.c
+++ b/src/readahead/readahead-common.c
@@ -210,7 +210,7 @@ finish:
 
 #define BUMP_REQUEST_NR (16*1024)
 
-int bump_request_nr(const char *p) {
+int block_bump_request_nr(const char *p) {
         struct stat st;
         uint64_t u;
         char *ap = NULL, *line = NULL;
@@ -267,3 +267,83 @@ finish:
 
         return r;
 }
+
+int block_get_readahead(const char *p, uint64_t *bytes) {
+        struct stat st;
+        char *ap = NULL, *line = NULL;
+        int r;
+        dev_t d;
+        uint64_t u;
+
+        assert(p);
+        assert(bytes);
+
+        if (stat(p, &st) < 0)
+                return -errno;
+
+        if (major(st.st_dev) == 0)
+                return 0;
+
+        d = st.st_dev;
+        block_get_whole_disk(d, &d);
+
+        if (asprintf(&ap, "/sys/dev/block/%u:%u/bdi/read_ahead_kb", major(d), minor(d)) < 0) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        r = read_one_line_file(ap, &line);
+        if (r < 0)
+                goto finish;
+
+        r = safe_atou64(line, &u);
+        if (r < 0)
+                goto finish;
+
+        *bytes = u * 1024ULL;
+
+finish:
+        free(ap);
+        free(line);
+
+        return r;
+}
+
+int block_set_readahead(const char *p, uint64_t bytes) {
+        struct stat st;
+        char *ap = NULL, *line = NULL;
+        int r;
+        dev_t d;
+
+        assert(p);
+        assert(bytes);
+
+        if (stat(p, &st) < 0)
+                return -errno;
+
+        if (major(st.st_dev) == 0)
+                return 0;
+
+        d = st.st_dev;
+        block_get_whole_disk(d, &d);
+
+        if (asprintf(&ap, "/sys/dev/block/%u:%u/bdi/read_ahead_kb", major(d), minor(d)) < 0) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (asprintf(&line, "%llu", (unsigned long long) bytes / 1024ULL) < 0) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        r = write_one_line_file(ap, line);
+        if (r < 0)
+                goto finish;
+
+finish:
+        free(ap);
+        free(line);
+
+        return r;
+}
diff --git a/src/readahead/readahead-common.h b/src/readahead/readahead-common.h
index b4eab71..9962dd5 100644
--- a/src/readahead/readahead-common.h
+++ b/src/readahead/readahead-common.h
@@ -45,6 +45,9 @@ typedef struct ReadaheadShared {
 
 ReadaheadShared *shared_get(void);
 
-int bump_request_nr(const char *p);
+int block_bump_request_nr(const char *p);
+
+int block_get_readahead(const char *p, uint64_t *bytes);
+int block_set_readahead(const char *p, uint64_t bytes);
 
 #endif
diff --git a/src/readahead/readahead-replay.c b/src/readahead/readahead-replay.c
index f91020e..0b7e6df 100644
--- a/src/readahead/readahead-replay.c
+++ b/src/readahead/readahead-replay.c
@@ -133,7 +133,7 @@ static int replay(const char *root) {
         assert(root);
 
         write_one_line_file("/proc/self/oom_score_adj", "1000");
-        bump_request_nr(root);
+        block_bump_request_nr(root);
 
         if (asprintf(&pack_fn, "%s/.readahead", root) < 0) {
                 log_error("Out of memory");

commit 37099707e26ef2c6d215f6e7f17dd46bf6aad586
Author: Lennart Poettering <lennart at poettering.net>
Date:   Thu May 3 23:23:38 2012 +0200

    cgroup: fix alloca() misuse in cg_shorten_controllers()

diff --git a/TODO b/TODO
index 2e33360..f2c5dd6 100644
--- a/TODO
+++ b/TODO
@@ -60,8 +60,6 @@ Features:
 
 * add RequiredBy to [Install]
 
-* cg_shorten_controllers() misuses alloca()
-
 * udev: move to LGPL
 
 * udev systemd unify:
diff --git a/src/shared/cgroup-util.c b/src/shared/cgroup-util.c
index d34c142..1f310d3 100644
--- a/src/shared/cgroup-util.c
+++ b/src/shared/cgroup-util.c
@@ -565,9 +565,23 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
         return join_path(p, path, suffix, fs);
 }
 
+static int check(const char *p) {
+        char *cc;
+
+        assert(p);
+
+        /* Check if this controller actually really exists */
+        cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(p));
+        strcpy(stpcpy(cc, "/sys/fs/cgroup/"), p);
+        if (access(cc, F_OK) < 0)
+                return -errno;
+
+        return 0;
+}
+
 int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs) {
         const char *p;
-        char *cc;
+        int r;
 
         assert(controller);
         assert(fs);
@@ -575,13 +589,13 @@ int cg_get_path_and_check(const char *controller, const char *path, const char *
         if (isempty(controller))
                 return -EINVAL;
 
+        /* Normalize the controller syntax */
         p = normalize_controller(controller);
 
         /* Check if this controller actually really exists */
-        cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(p));
-        strcpy(stpcpy(cc, "/sys/fs/cgroup/"), p);
-        if (access(cc, F_OK) < 0)
-                return -errno;
+        r = check(p);
+        if (r < 0)
+                return r;
 
         return join_path(p, path, suffix, fs);
 }
@@ -1111,17 +1125,18 @@ char **cg_shorten_controllers(char **controllers) {
                 return controllers;
 
         for (f = controllers, t = controllers; *f; f++) {
-                char *cc;
+                int r;
+                const char *p;
 
                 if (streq(*f, "systemd") || streq(*f, SYSTEMD_CGROUP_CONTROLLER)) {
                         free(*f);
                         continue;
                 }
 
-                cc = alloca(sizeof("/sys/fs/cgroup/") + strlen(*f));
-                strcpy(stpcpy(cc, "/sys/fs/cgroup/"), *f);
+                p = normalize_controller(*f);
 
-                if (access(cc, F_OK) < 0) {
+                r = check(p);
+                if (r < 0) {
                         log_debug("Controller %s is not available, removing from controllers list.", *f);
                         free(*f);
                         continue;



More information about the systemd-commits mailing list