]> git.proxmox.com Git - mirror_lxcfs.git/blobdiff - lxcfs.c
Remove unused chunks in caching code
[mirror_lxcfs.git] / lxcfs.c
diff --git a/lxcfs.c b/lxcfs.c
index 4834640e9f79c7c65d12306be83ed41ba1ea17c0..a1470bf2a3e1154daa3cc84c23067e6b517a4e09 100644 (file)
--- a/lxcfs.c
+++ b/lxcfs.c
@@ -1,6 +1,6 @@
 /* lxcfs
  *
- * Copyright © 2014,2015 Canonical, Inc
+ * Copyright © 2014-2016 Canonical, Inc
  * Author: Serge Hallyn <serge.hallyn@ubuntu.com>
  *
  * See COPYING file for details.
@@ -20,6 +20,7 @@
 #include <stdlib.h>
 #include <libgen.h>
 #include <sched.h>
+#include <pthread.h>
 #include <linux/sched.h>
 #include <sys/socket.h>
 #include <sys/mount.h>
@@ -59,37 +60,326 @@ struct file_info {
 #define BUF_RESERVE_SIZE 256
 
 /*
- * append pid to *src.
- * src: a pointer to a char* in which ot append the pid.
- * sz: the number of characters printed so far, minus trailing \0.
- * asz: the allocated size so far
- * pid: the pid to append
+ * A table caching which pid is init for a pid namespace.
+ * When looking up which pid is init for $qpid, we first
+ * 1. Stat /proc/$qpid/ns/pid.
+ * 2. Check whether the ino_t is in our store.
+ *   a. if not, fork a child in qpid's ns to send us
+ *      ucred.pid = 1, and read the initpid.  Cache
+ *      initpid and creation time for /proc/initpid
+ *      in a new store entry.
+ *   b. if so, verify that /proc/initpid still matches
+ *      what we have saved.  If not, clear the store
+ *      entry and go back to a.  If so, return the
+ *      cached initpid.
  */
-static void must_strcat_pid(char **src, size_t *sz, size_t *asz, pid_t pid)
+struct pidns_init_store {
+       ino_t ino;          // inode number for /proc/$pid/ns/pid
+       pid_t initpid;      // the pid of nit in that ns
+       long int ctime;     // the time at which /proc/$initpid was created
+       struct pidns_init_store *next;
+       long int lastcheck;
+};
+
+/* lol - look at how they are allocated in the kernel */
+#define PIDNS_HASH_SIZE 4096
+#define HASH(x) ((x) % PIDNS_HASH_SIZE)
+
+struct pidns_init_store *pidns_hash_table[PIDNS_HASH_SIZE];
+static pthread_mutex_t pidns_store_mutex = PTHREAD_MUTEX_INITIALIZER;
+static void lock_mutex(pthread_mutex_t *l)
 {
-       char tmp[30];
+       int ret;
 
-       int tmplen = sprintf(tmp, "%d\n", (int)pid);
+       if ((ret = pthread_mutex_lock(l)) != 0) {
+               fprintf(stderr, "pthread_mutex_lock returned:%d %s\n", ret, strerror(ret));
+               exit(1);
+       }
+}
 
-       if (!*src || tmplen + *sz + 1 >= *asz) {
-               char *tmp;
-               do {
-                       tmp = realloc(*src, *asz + BUF_RESERVE_SIZE);
-               } while (!tmp);
-               *src = tmp;
-               *asz += BUF_RESERVE_SIZE;
+static void unlock_mutex(pthread_mutex_t *l)
+{
+       int ret;
+
+       if ((ret = pthread_mutex_unlock(l)) != 0) {
+               fprintf(stderr, "pthread_mutex_unlock returned:%d %s\n", ret, strerror(ret));
+               exit(1);
        }
-       memcpy((*src) +*sz , tmp, tmplen);
-       *sz += tmplen;
-       (*src)[*sz] = '\0';
 }
 
-static pid_t get_init_pid_for_task(pid_t task);
+static void store_lock(void)
+{
+       lock_mutex(&pidns_store_mutex);
+}
+
+static void store_unlock(void)
+{
+       unlock_mutex(&pidns_store_mutex);
+}
+
+/* Must be called under store_lock */
+static bool initpid_still_valid(struct pidns_init_store *e, struct stat *nsfdsb)
+{
+       struct stat initsb;
+       char fnam[100];
+
+       snprintf(fnam, 100, "/proc/%d", e->initpid);
+       if (stat(fnam, &initsb) < 0)
+               return false;
+#if DEBUG
+       fprintf(stderr, "comparing ctime %ld %ld for pid %d\n",
+               e->ctime, initsb.st_ctime, e->initpid);
+#endif
+       if (e->ctime != initsb.st_ctime)
+               return false;
+       return true;
+}
+
+/* Must be called under store_lock */
+static void remove_initpid(struct pidns_init_store *e)
+{
+       struct pidns_init_store *tmp;
+       int h;
+
+#if DEBUG
+       fprintf(stderr, "remove_initpid: removing entry for %d\n", e->initpid);
+#endif
+       h = HASH(e->ino);
+       if (pidns_hash_table[h] == e) {
+               pidns_hash_table[h] = e->next;
+               free(e);
+               return;
+       }
+
+       tmp = pidns_hash_table[h];
+       while (tmp) {
+               if (tmp->next == e) {
+                       tmp->next = e->next;
+                       free(e);
+                       return;
+               }
+               tmp = tmp->next;
+       }
+}
+
+#define PURGE_SECS 5
+/* Must be called under store_lock */
+static void prune_initpid_store(void)
+{
+       static long int last_prune = 0;
+       struct pidns_init_store *e, *prev, *delme;
+       long int now, threshold;
+       int i;
+
+       if (!last_prune) {
+               last_prune = time(NULL);
+               return;
+       }
+       now = time(NULL);
+       if (now < last_prune + PURGE_SECS)
+               return;
+#if DEBUG
+       fprintf(stderr, "pruning\n");
+#endif
+       last_prune = now;
+       threshold = now - 2 * PURGE_SECS;
+
+       for (i = 0; i < PIDNS_HASH_SIZE; i++) {
+               for (prev = NULL, e = pidns_hash_table[i]; e; ) {
+                       if (e->lastcheck < threshold) {
+#if DEBUG
+                               fprintf(stderr, "Removing cached entry for %d\n", e->initpid);
+#endif
+                               delme = e;
+                               if (prev)
+                                       prev->next = e->next;
+                               else
+                                       pidns_hash_table[i] = e->next;
+                               e = e->next;
+                               free(delme);
+                       } else {
+                               prev = e;
+                               e = e->next;
+                       }
+               }
+       }
+}
+
+/* Must be called under store_lock */
+static void save_initpid(struct stat *sb, pid_t pid)
+{
+       struct pidns_init_store *e;
+       char fpath[100];
+       struct stat procsb;
+       int h;
+
+#if DEBUG
+       fprintf(stderr, "save_initpid: adding entry for %d\n", pid);
+#endif
+       snprintf(fpath, 100, "/proc/%d", pid);
+       if (stat(fpath, &procsb) < 0)
+               return;
+       do {
+               e = malloc(sizeof(*e));
+       } while (!e);
+       e->ino = sb->st_ino;
+       e->initpid = pid;
+       e->ctime = procsb.st_ctime;
+       h = HASH(e->ino);
+       e->next = pidns_hash_table[h];
+       e->lastcheck = time(NULL);
+       pidns_hash_table[h] = e;
+}
+
+/*
+ * Given the stat(2) info for a nsfd pid inode, lookup the init_pid_store
+ * entry for the inode number and creation time.  Verify that the init pid
+ * is still valid.  If not, remove it.  Return the entry if valid, NULL
+ * otherwise.
+ * Must be called under store_lock
+ */
+static struct pidns_init_store *lookup_verify_initpid(struct stat *sb)
+{
+       int h = HASH(sb->st_ino);
+       struct pidns_init_store *e = pidns_hash_table[h];
+
+       while (e) {
+               if (e->ino == sb->st_ino) {
+                       if (initpid_still_valid(e, sb)) {
+                               e->lastcheck = time(NULL);
+                               return e;
+                       }
+                       remove_initpid(e);
+                       return NULL;
+               }
+               e = e->next;
+       }
+
+       return NULL;
+}
+
+#define SEND_CREDS_OK 0
+#define SEND_CREDS_NOTSK 1
+#define SEND_CREDS_FAIL 2
+static bool recv_creds(int sock, struct ucred *cred, char *v);
+static int wait_for_pid(pid_t pid);
+static int send_creds(int sock, struct ucred *cred, char v, bool pingfirst);
+
+/*
+ * fork a task which switches to @task's namespace and writes '1'.
+ * over a unix sock so we can read the task's reaper's pid in our
+ * namespace
+ */
+static void write_task_init_pid_exit(int sock, pid_t target)
+{
+       struct ucred cred;
+       char fnam[100];
+       pid_t pid;
+       char v;
+       int fd, ret;
+
+       ret = snprintf(fnam, sizeof(fnam), "/proc/%d/ns/pid", (int)target);
+       if (ret < 0 || ret >= sizeof(fnam))
+               _exit(1);
+
+       fd = open(fnam, O_RDONLY);
+       if (fd < 0) {
+               perror("write_task_init_pid_exit open of ns/pid");
+               _exit(1);
+       }
+       if (setns(fd, 0)) {
+               perror("write_task_init_pid_exit setns 1");
+               close(fd);
+               _exit(1);
+       }
+       pid = fork();
+       if (pid < 0)
+               _exit(1);
+       if (pid != 0) {
+               if (!wait_for_pid(pid))
+                       _exit(1);
+               _exit(0);
+       }
+
+       /* we are the child */
+       cred.uid = 0;
+       cred.gid = 0;
+       cred.pid = 1;
+       v = '1';
+       if (send_creds(sock, &cred, v, true) != SEND_CREDS_OK)
+               _exit(1);
+       _exit(0);
+}
+
+static pid_t get_init_pid_for_task(pid_t task)
+{
+       int sock[2];
+       pid_t pid;
+       pid_t ret = -1;
+       char v = '0';
+       struct ucred cred;
+
+       if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sock) < 0) {
+               perror("socketpair");
+               return -1;
+       }
+
+       pid = fork();
+       if (pid < 0)
+               goto out;
+       if (!pid) {
+               close(sock[1]);
+               write_task_init_pid_exit(sock[0], task);
+               _exit(0);
+       }
+
+       if (!recv_creds(sock[1], &cred, &v))
+               goto out;
+       ret = cred.pid;
+
+out:
+       close(sock[0]);
+       close(sock[1]);
+       if (pid > 0)
+               wait_for_pid(pid);
+       return ret;
+}
+
+static pid_t lookup_initpid_in_store(pid_t qpid)
+{
+       pid_t answer = 0;
+       struct stat sb;
+       struct pidns_init_store *e;
+       char fnam[100];
+
+       snprintf(fnam, 100, "/proc/%d/ns/pid", qpid);
+       store_lock();
+       if (stat(fnam, &sb) < 0)
+               goto out;
+       e = lookup_verify_initpid(&sb);
+       if (e) {
+               answer = e->initpid;
+               goto out;
+       }
+       answer = get_init_pid_for_task(qpid);
+       if (answer > 0)
+               save_initpid(&sb, answer);
+
+out:
+       /* we prune at end in case we are returning
+        * the value we were about to return */
+       prune_initpid_store();
+       store_unlock();
+       return answer;
+}
 
 static int wait_for_pid(pid_t pid)
 {
        int status, ret;
 
+       if (pid <= 0)
+               return -1;
+
 again:
        ret = waitpid(pid, &status, 0);
        if (ret == -1) {
@@ -104,6 +394,33 @@ again:
        return 0;
 }
 
+
+/*
+ * append pid to *src.
+ * src: a pointer to a char* in which ot append the pid.
+ * sz: the number of characters printed so far, minus trailing \0.
+ * asz: the allocated size so far
+ * pid: the pid to append
+ */
+static void must_strcat_pid(char **src, size_t *sz, size_t *asz, pid_t pid)
+{
+       char tmp[30];
+
+       int tmplen = sprintf(tmp, "%d\n", (int)pid);
+
+       if (!*src || tmplen + *sz + 1 >= *asz) {
+               char *tmp;
+               do {
+                       tmp = realloc(*src, *asz + BUF_RESERVE_SIZE);
+               } while (!tmp);
+               *src = tmp;
+               *asz += BUF_RESERVE_SIZE;
+       }
+       memcpy((*src) +*sz , tmp, tmplen);
+       *sz += tmplen;
+       (*src)[*sz] = '\0';
+}
+
 /*
  * Given a open file * to /proc/pid/{u,g}id_map, and an id
  * valid in the caller's namespace, return the id mapped into
@@ -347,9 +664,12 @@ out:
 static void prune_init_slice(char *cg)
 {
        char *point;
-       point = cg + strlen(cg) - strlen(INITSCOPE);
-       if (point < cg)
-                return;
+       size_t cg_len = strlen(cg), initscope_len = strlen(INITSCOPE);
+
+       if (cg_len < initscope_len)
+               return;
+
+       point = cg + cg_len - initscope_len;
        if (strcmp(point, INITSCOPE) == 0) {
                if (point == cg)
                        *(point+1) = '\0';
@@ -359,8 +679,8 @@ static void prune_init_slice(char *cg)
 }
 
 /*
- * If caller is in /a/b/c/d, he may only act on things under cg=/a/b/c/d.
- * If caller is in /a, he may act on /a/b, but not on /b.
+ * If pid is in /a/b/c/d, he may only act on things under cg=/a/b/c/d.
+ * If pid is in /a, he may act on /a/b, but not on /b.
  * if the answer is false and nextcg is not NULL, then *nextcg will point
  * to a string containing the next cgroup directory under cg, which must be
  * freed by the caller.
@@ -394,7 +714,7 @@ out:
 }
 
 /*
- * If caller is in /a/b/c, he may see that /a exists, but not /b or /a/c.
+ * If pid is in /a/b/c, he may see that /a exists, but not /b or /a/c.
  */
 static bool caller_may_see_dir(pid_t pid, const char *contrl, const char *cg)
 {
@@ -564,16 +884,19 @@ static int cg_getattr(const char *path, struct stat *sb)
                path2 = last;
        }
 
+       pid_t initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
        /* check that cgcopy is either a child cgroup of cgdir, or listed in its keys.
         * Then check that caller's cgroup is under path if last is a child
         * cgroup, or cgdir if last is a file */
 
        if (is_child_cgroup(controller, path1, path2)) {
-               if (!caller_may_see_dir(fc->pid, controller, cgroup)) {
+               if (!caller_may_see_dir(initpid, controller, cgroup)) {
                        ret = -ENOENT;
                        goto out;
                }
-               if (!caller_is_in_ancestor(fc->pid, controller, cgroup, NULL)) {
+               if (!caller_is_in_ancestor(initpid, controller, cgroup, NULL)) {
                        /* this is just /cgroup/controller, return it as a dir */
                        sb->st_mode = S_IFDIR | 00555;
                        sb->st_nlink = 2;
@@ -608,7 +931,7 @@ static int cg_getattr(const char *path, struct stat *sb)
                sb->st_gid = k->gid;
                sb->st_size = 0;
                free_key(k);
-               if (!caller_is_in_ancestor(fc->pid, controller, path1, NULL)) {
+               if (!caller_is_in_ancestor(initpid, controller, path1, NULL)) {
                        ret = -ENOENT;
                        goto out;
                }
@@ -651,8 +974,11 @@ static int cg_opendir(const char *path, struct fuse_file_info *fi)
                }
        }
 
+       pid_t initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
        if (cgroup) {
-               if (!caller_may_see_dir(fc->pid, controller, cgroup))
+               if (!caller_may_see_dir(initpid, controller, cgroup))
                        return -ENOENT;
                if (!fc_may_access(fc, controller, cgroup, NULL, O_RDONLY))
                        return -EACCES;
@@ -705,7 +1031,10 @@ static int cg_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t
                goto out;
        }
 
-       if (!caller_is_in_ancestor(fc->pid, d->controller, d->cgroup, &nextcg)) {
+       pid_t initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
+       if (!caller_is_in_ancestor(initpid, d->controller, d->cgroup, &nextcg)) {
                if (nextcg) {
                        int ret;
                        ret = filler(buf, nextcg,  NULL, 0);
@@ -804,7 +1133,10 @@ static int cg_open(const char *path, struct fuse_file_info *fi)
        }
        free_key(k);
 
-       if (!caller_may_see_dir(fc->pid, controller, path1)) {
+       pid_t initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
+       if (!caller_may_see_dir(initpid, controller, path1)) {
                ret = -ENOENT;
                goto out;
        }
@@ -848,10 +1180,12 @@ static int cg_release(const char *path, struct fuse_file_info *fi)
 static bool wait_for_sock(int sock, int timeout)
 {
        struct epoll_event ev;
-       int epfd, ret;
+       int epfd, ret, now, starttime, deltatime, saved_errno;
+
+       if ((starttime = time(NULL)) < 0)
+               return false;
 
-       epfd = epoll_create(1);
-       if (epfd < 0) {
+       if ((epfd = epoll_create(1)) < 0) {
                fprintf(stderr, "Failed to create epoll socket: %m\n");
                return false;
        }
@@ -864,13 +1198,26 @@ static bool wait_for_sock(int sock, int timeout)
                return false;
        }
 
-       ret = epoll_wait(epfd, &ev, 1, timeout);
-       close(epfd);
+again:
+       if ((now = time(NULL)) < 0) {
+               close(epfd);
+               return false;
+       }
 
-       if (ret == 0)
+       deltatime = (starttime + timeout) - now;
+       if (deltatime < 0) { // timeout
+               errno = 0;
+               close(epfd);
                return false;
-       if (ret < 0) {
-               fprintf(stderr, "Failure during epoll_wait: %m\n");
+       }
+       ret = epoll_wait(epfd, &ev, 1, 1000*deltatime + 1);
+       if (ret < 0 && errno == EINTR)
+               goto again;
+       saved_errno = errno;
+       close(epfd);
+
+       if (ret <= 0) {
+               errno = saved_errno;
                return false;
        }
        return true;
@@ -883,9 +1230,6 @@ static int msgrecv(int sockfd, void *buf, size_t len)
        return recv(sockfd, buf, len, MSG_DONTWAIT);
 }
 
-#define SEND_CREDS_OK 0
-#define SEND_CREDS_NOTSK 1
-#define SEND_CREDS_FAIL 2
 static int send_creds(int sock, struct ucred *cred, char v, bool pingfirst)
 {
        struct msghdr msg = { 0 };
@@ -1295,7 +1639,7 @@ loop:
        }
 
        // give the child 1 second to be done forking and
-       // write it's ack
+       // write its ack
        if (!wait_for_sock(cpipe[0], 1))
                goto again;
        ret = read(cpipe[0], &v, 1);
@@ -1689,8 +2033,13 @@ int cg_mkdir(const char *path, mode_t mode)
        else
                path1 = cgdir;
 
-       if (!caller_is_in_ancestor(fc->pid, controller, path1, &next)) {
-               if (last && strcmp(next, last) == 0)
+       pid_t initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
+       if (!caller_is_in_ancestor(initpid, controller, path1, &next)) {
+               if (!next)
+                       ret = -EINVAL;
+               else if (last && strcmp(next, last) == 0)
                        ret = -EEXIST;
                else
                        ret = -ENOENT;
@@ -1701,7 +2050,7 @@ int cg_mkdir(const char *path, mode_t mode)
                ret = -EACCES;
                goto out;
        }
-       if (!caller_is_in_ancestor(fc->pid, controller, path1, NULL)) {
+       if (!caller_is_in_ancestor(initpid, controller, path1, NULL)) {
                ret = -EACCES;
                goto out;
        }
@@ -1738,7 +2087,10 @@ static int cg_rmdir(const char *path)
                goto out;
        }
 
-       if (!caller_is_in_ancestor(fc->pid, controller, cgroup, &next)) {
+       pid_t initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
+       if (!caller_is_in_ancestor(initpid, controller, cgroup, &next)) {
                if (!last || strcmp(next, last) == 0)
                        ret = -EBUSY;
                else
@@ -1750,7 +2102,7 @@ static int cg_rmdir(const char *path)
                ret = -EACCES;
                goto out;
        }
-       if (!caller_is_in_ancestor(fc->pid, controller, cgroup, NULL)) {
+       if (!caller_is_in_ancestor(initpid, controller, cgroup, NULL)) {
                ret = -EACCES;
                goto out;
        }
@@ -1839,16 +2191,9 @@ static int read_file(const char *path, char *buf, size_t size,
                        rv = 0;
                        goto err;
                }
-               if (l < cache_size) {
-                       cache += l;
-                       cache_size -= l;
-                       total_len += l;
-               } else {
-                       cache += cache_size;
-                       total_len += cache_size;
-                       cache_size = 0;
-                       break;
-               }
+               cache += l;
+               cache_size -= l;
+               total_len += l;
        }
 
        d->size = total_len;
@@ -1925,7 +2270,10 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset,
                return total_len;
        }
 
-       cg = get_pid_cgroup(fc->pid, "memory");
+       pid_t initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
+       cg = get_pid_cgroup(initpid, "memory");
        if (!cg)
                return read_file("/proc/meminfo", buf, size, d);
 
@@ -2104,7 +2452,10 @@ static int proc_cpuinfo_read(char *buf, size_t size, off_t offset,
                return total_len;
        }
 
-       cg = get_pid_cgroup(fc->pid, "cpuset");
+       pid_t initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
+       cg = get_pid_cgroup(initpid, "cpuset");
        if (!cg)
                return read_file("proc/cpuinfo", buf, size, d);
 
@@ -2133,16 +2484,9 @@ static int proc_cpuinfo_read(char *buf, size_t size, off_t offset,
                                        rv = 0;
                                        goto err;
                                }
-                               if (l < cache_size){
-                                       cache += l;
-                                       cache_size -= l;
-                                       total_len += l;
-                               }else{
-                                       cache += cache_size;
-                                       total_len += cache_size;
-                                       cache_size = 0;
-                                       break;
-                               }
+                               cache += l;
+                               cache_size -= l;
+                               total_len += l;
                        }
                        continue;
                }
@@ -2158,16 +2502,9 @@ static int proc_cpuinfo_read(char *buf, size_t size, off_t offset,
                                rv = 0;
                                goto err;
                        }
-                       if (l < cache_size) {
-                               cache += l;
-                               cache_size -= l;
-                               total_len += l;
-                       } else {
-                               cache += cache_size;
-                               total_len += cache_size;
-                               cache_size = 0;
-                               break;
-                       }
+                       cache += l;
+                       cache_size -= l;
+                       total_len += l;
                }
        }
 
@@ -2218,7 +2555,10 @@ static int proc_stat_read(char *buf, size_t size, off_t offset,
                return total_len;
        }
 
-       cg = get_pid_cgroup(fc->pid, "cpuset");
+       pid_t initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
+       cg = get_pid_cgroup(initpid, "cpuset");
        if (!cg)
                return read_file("/proc/stat", buf, size, d);
 
@@ -2255,18 +2595,10 @@ static int proc_stat_read(char *buf, size_t size, off_t offset,
                                rv = 0;
                                goto err;
                        }
-                       if (l < cache_size) {
-                               cache += l;
-                               cache_size -= l;
-                               total_len += l;
-                               continue;
-                       } else {
-                               //no more space, break it
-                               cache += cache_size;
-                               total_len += cache_size;
-                               cache_size = 0;
-                               break;
-                       }
+                       cache += l;
+                       cache_size -= l;
+                       total_len += l;
+                       continue;
                }
 
                if (sscanf(cpu_char, "%d", &cpu) != 1)
@@ -2347,8 +2679,8 @@ static long int getreaperage(pid_t pid)
        int ret;
        pid_t qpid;
 
-       qpid = get_init_pid_for_task(pid);
-       if (qpid < 0)
+       qpid = lookup_initpid_in_store(pid);
+       if (qpid <= 0)
                return 0;
 
        ret = snprintf(fnam, 100, "/proc/%d", qpid);
@@ -2361,92 +2693,16 @@ static long int getreaperage(pid_t pid)
        return time(NULL) - sb.st_ctime;
 }
 
-/*
- * fork a task which switches to @task's namespace and writes '1'.
- * over a unix sock so we can read the task's reaper's pid in our
- * namespace
- */
-void write_task_init_pid_exit(int sock, pid_t target)
-{
-       struct ucred cred;
-       char fnam[100];
-       pid_t pid;
-       char v;
-       int fd, ret;
-
-       ret = snprintf(fnam, sizeof(fnam), "/proc/%d/ns/pid", (int)target);
-       if (ret < 0 || ret >= sizeof(fnam))
-               _exit(1);
-
-       fd = open(fnam, O_RDONLY);
-       if (fd < 0) {
-               perror("write_task_init_pid_exit open of ns/pid");
-               _exit(1);
-       }
-       if (setns(fd, 0)) {
-               perror("write_task_init_pid_exit setns 1");
-               close(fd);
-               _exit(1);
-       }
-       pid = fork();
-       if (pid < 0)
-               _exit(1);
-       if (pid != 0) {
-               wait_for_pid(pid);
-               _exit(0);
-       }
-
-       /* we are the child */
-       cred.uid = 0;
-       cred.gid = 0;
-       cred.pid = 1;
-       v = '1';
-       send_creds(sock, &cred, v, true);
-       _exit(0);
-}
-
-static pid_t get_init_pid_for_task(pid_t task)
-{
-       int sock[2];
-       pid_t pid;
-       pid_t ret = -1;
-       char v = '0';
-       struct ucred cred;
-
-       if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sock) < 0) {
-               perror("socketpair");
-               return -1;
-       }
-
-       pid = fork();
-       if (pid < 0)
-               goto out;
-       if (!pid) {
-               close(sock[1]);
-               write_task_init_pid_exit(sock[0], task);
-       }
-
-       if (!recv_creds(sock[1], &cred, &v))
-               goto out;
-       ret = cred.pid;
-
-out:
-       close(sock[0]);
-       close(sock[1]);
-       wait_for_pid(pid);
-       return ret;
-}
-
 static unsigned long get_reaper_busy(pid_t task)
 {
-       pid_t init = get_init_pid_for_task(task);
+       pid_t initpid = lookup_initpid_in_store(task);
        char *cgroup = NULL, *usage_str = NULL;
        unsigned long usage = 0;
 
-       if (init == -1)
+       if (initpid <= 0)
                return 0;
 
-       cgroup = get_pid_cgroup(init, "cpuacct");
+       cgroup = get_pid_cgroup(initpid, "cpuacct");
        if (!cgroup)
                goto out;
        if (!cgfs_get_value("cpuacct", cgroup, "cpuacct.usage", &usage_str))
@@ -2539,7 +2795,10 @@ static int proc_diskstats_read(char *buf, size_t size, off_t offset,
                return total_len;
        }
 
-       cg = get_pid_cgroup(fc->pid, "blkio");
+       pid_t initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
+       cg = get_pid_cgroup(initpid, "blkio");
        if (!cg)
                return read_file("/proc/diskstats", buf, size, d);