]> git.proxmox.com Git - mirror_lxcfs.git/commitdiff
Merge pull request #558 from tych0/cpu-num-proc-stat
authorStéphane Graber <stgraber@ubuntu.com>
Wed, 4 Jan 2023 17:20:15 +0000 (12:20 -0500)
committerGitHub <noreply@github.com>
Wed, 4 Jan 2023 17:20:15 +0000 (12:20 -0500)
/proc/stat: render physical cpu number in non-view mode

13 files changed:
.github/workflows/builds.yml
.github/workflows/tests.yml
README.md
config/init/meson.build
src/bindings.c
src/bindings.h
src/cpuset_parse.c
src/lxcfs.c
src/macro.h
src/proc_cpuview.c
src/proc_fuse.c
src/utils.c
src/utils.h

index 5b2b868438e781054766467b99ee25ba6c57c7be..84b01436fb7252f961e35754819b21abcc9243fa 100644 (file)
@@ -36,11 +36,9 @@ jobs:
           export PATH="$(pwd)/cov-analysis-linux64/bin:${PATH}"
 
           meson setup -Ddocs=false -Dtests=true -Dinit-script=systemd -Dprefix=/usr build/
-          meson compile -C build
-          cd build
 
           # Build
-          cov-build --dir cov-int make -j4
+          cov-build --dir cov-int ninja -C build
           tar czvf lxcfs.tgz cov-int
 
           # Submit the results
index 204b5c8634e30b9d2b14b52f5ec23264352b9138..21a0c8760de18369704ea825fc1944c961306c2b 100644 (file)
@@ -41,7 +41,7 @@ jobs:
         env:
           CC: ${{ matrix.compiler }}
         run: |
-          meson setup -Ddocs=false -Dtests=true -Dinit-script=systemd -Dprefix=/usr build/
+          meson setup -Ddocs=false -Dtests=true -Dinit-script=systemd -Dprefix=/usr -Db_sanitize=address,undefined build/
           meson compile -C build
       - name: Test
         env:
@@ -84,7 +84,7 @@ jobs:
         env:
           CC: ${{ matrix.compiler }}
         run: |
-          meson setup -Ddocs=false -Dtests=true -Dinit-script=systemd -Dprefix=/usr build/
+          meson setup -Ddocs=false -Dtests=true -Dinit-script=systemd -Dprefix=/usr -Db_sanitize=address,undefined build/
           meson compile -C build
       - name: Test
         env:
index 50045e02ad4df627e5fdf1657c65919d4c3d9be3..722948f294a6894b9ba25dc1a0c51f4d80c36e5c 100644 (file)
--- a/README.md
+++ b/README.md
@@ -71,6 +71,12 @@ versions:
     meson compile -C build/
     sudo meson install -C build/
 
+To build with sanitizers you have to specify `-Db_sanitize=...` option to `meson setup`.
+For example, to enable ASAN and UBSAN:
+
+    meson setup -Dinit-script=systemd --prefix=/usr build/ -Db_sanitize=address,undefined
+    meson compile -C build/
+
 ## Usage
 The recommended command to run lxcfs is:
 
@@ -104,6 +110,7 @@ docker run -it -m 256m --memory-swap 256m \
       -v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw \
       -v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw \
       -v /var/lib/lxcfs/proc/slabinfo:/proc/slabinfo:rw \
+      -v /var/lib/lxcfs/sys/devices/system/cpu:/sys/devices/system/cpu:rw \
       ubuntu:18.04 /bin/bash
  ```
 
index 5200570bee309ee0d1b6bf49a4372592e571baff..8445955cbd515c93c021897074d2070c61b20f3c 100644 (file)
@@ -2,7 +2,7 @@
 
 if 'systemd' in init_script
     systemd = dependency('systemd')
-    systemd_system_unit_dir = systemd.get_pkgconfig_variable('systemdsystemunitdir')
+    systemd_system_unit_dir = get_option('prefix') + systemd.get_pkgconfig_variable('systemdsystemunitdir')
     systemd_service = custom_target(
         'lxcfs.service',
         input: 'systemd/lxcfs.service.in',
index fee7ede0dab672cf2a844fe3f0ccf3974f2f4b26..13259c1be9277b56c797826e89625a34af0b7694 100644 (file)
@@ -45,6 +45,7 @@ static bool can_use_swap;
 static bool can_use_sys_cpu;
 static bool has_versioned_opts;
 static bool memory_is_cgroupv2;
+static __u32 host_personality;
 
 static volatile sig_atomic_t reload_successful;
 
@@ -73,6 +74,11 @@ bool liblxcfs_memory_is_cgroupv2(void)
        return memory_is_cgroupv2;
 }
 
+__u32 liblxcfs_personality(void)
+{
+       return host_personality;
+}
+
 /* Define pivot_root() if missing from the C library */
 #ifndef HAVE_PIVOT_ROOT
 static int pivot_root(const char *new_root, const char *put_old)
@@ -424,7 +430,7 @@ __returns_twice pid_t lxcfs_raw_clone(unsigned long flags, int *pidfd)
        }
 #elif defined(__ia64__)
        /* On ia64 the stack and stack size are passed as separate arguments. */
-       return syscall(__NR_clone, flags | SIGCHLD, NULL, prctl_arg(0), pidfd);
+       return syscall(__NR_clone, flags | SIGCHLD, NULL, 0, pidfd);
 #else
        return syscall(__NR_clone, flags | SIGCHLD, NULL, pidfd);
 #endif
@@ -919,6 +925,11 @@ static void __attribute__((constructor)) lxcfs_init(void)
                goto broken_upgrade;
        }
 
+       if (get_task_personality(getpid(), &host_personality) < 0) {
+               lxcfs_info("Failed to retrieve host personality");
+               goto broken_upgrade;
+       }
+
        reload_successful = 1;
        return;
 
index e35423ac5da32fce9cbca29758232b0b05383a08..1624784e2870e3f2527afdfd53b5c0bc7a169c52 100644 (file)
@@ -107,6 +107,7 @@ extern bool liblxcfs_can_use_swap(void);
 extern bool liblxcfs_memory_is_cgroupv2(void);
 extern bool liblxcfs_can_use_sys_cpu(void);
 extern bool liblxcfs_has_versioned_opts(void);
+extern __u32 liblxcfs_personality(void);
 
 static inline bool lxcfs_has_opt(struct lxcfs_opts *opts, lxcfs_opt_t opt)
 {
index e511bb021745c78837dfef4eb34646f3571a8a58..9ff016b039e4ec68e4f62153e79a5086819c9e4b 100644 (file)
@@ -18,6 +18,9 @@ static char *cpuset_nexttok(const char *c)
 {
        char *r;
 
+       if (!strlen(c))
+               return NULL;
+
        r = strchr(c + 1, ',');
        return r ? (r + 1) : NULL;
 }
index fed896c965835ae14c4dc1219aff6b3297035cf0..c6f83a84c550aaa4176b6c8825a626907f8704ca 100644 (file)
@@ -1030,6 +1030,10 @@ static void *lxcfs_init(struct fuse_conn_info *conn)
        if (lxcfs_init_library() < 0)
                return NULL;
 
+#if HAVE_FUSE3
+       cfg->direct_io = 1;
+#endif
+
        return fuse_get_context()->private_data;
 }
 
@@ -1343,7 +1347,7 @@ int main(int argc, char *argv[])
        }
 
        if (append_comma_separate(&new_fuse_opts, "direct_io")) {
-               lxcfs_error("Failed to copy fuse argument \"nonempty\"");
+               lxcfs_error("Failed to copy fuse argument \"direct_io\"");
                goto out;
        }
 #endif
index 36f23924ae49c1890bfa5f7ff99d035ca2b0edb7..9e2808ba096494ccbe5112ed9f6907952eb7e9e3 100644 (file)
                                    ? 20          \
                                    : sizeof(int[-2 * (sizeof(type) > 8)])))
 
+#define strnprintf(buf, buf_size, ...)                                                    \
+       ({                                                                                \
+               int __ret_strnprintf;                                                     \
+               __ret_strnprintf = snprintf(buf, buf_size, ##__VA_ARGS__);                \
+               if (__ret_strnprintf < 0 || (size_t)__ret_strnprintf >= (size_t)buf_size) \
+                       __ret_strnprintf = ret_errno(EIO);                                \
+               __ret_strnprintf;                                                         \
+       })
+
 #define move_ptr(ptr)                                 \
        ({                                            \
                __typeof__(ptr) __internal_ptr__ = (ptr); \
index db69de81ce8d6f5a2428f96e13a0e45865120819..678c937820ba7c38aaac12472feb1900ebfff244 100644 (file)
@@ -171,6 +171,7 @@ static struct cg_proc_stat *add_proc_stat_node(struct cg_proc_stat *new_node)
        }
 
 out_rwlock_unlock:
+       pthread_mutex_lock(&rv->lock);
        pthread_rwlock_unlock(&head->lock);
        return move_ptr(rv);
 }
@@ -224,6 +225,7 @@ static bool cgroup_supports(const char *controller, const char *cgroup,
        return faccessat(cfd, path, F_OK, 0) == 0;
 }
 
+/* should be called with wr-locked list */
 static struct cg_proc_stat *prune_proc_stat_list(struct cg_proc_stat *node)
 {
        struct cg_proc_stat *first = NULL;
@@ -232,6 +234,31 @@ static struct cg_proc_stat *prune_proc_stat_list(struct cg_proc_stat *node)
                if (!cgroup_supports("cpu", node->cg, "cpu.shares")) {
                        struct cg_proc_stat *cur = node;
 
+                       /*
+                        * We need to ensure that no one referenced this node,
+                        * because we are going to remove it from the list and free memory.
+                        *
+                        * If we can't grab the lock then just keep this node for now.
+                        */
+                       if (pthread_mutex_trylock(&cur->lock))
+                               goto next;
+
+                       /*
+                        * Yes, we can put lock back just after taking it, as we ensured
+                        * that we are only one user of it right now.
+                        *
+                        * It follows from three facts:
+                        * - we are under pthread_rwlock_wrlock(hash_table_bucket)
+                        * - pthread_mutex_lock is taken by find_proc_stat_node()
+                        * with pthread_rwlock_rdlock(hash_table_bucket) held.
+                        * - pthread_mutex_lock is taken by add_proc_stat_node()
+                        * with pthread_rwlock_wrlock(hash_table_bucket) held.
+                        *
+                        * It means that nobody can get a pointer to (cur) node in a parallel
+                        * thread and all old users of (cur) node have released pthread_mutex_lock(cur).
+                        */
+                       pthread_mutex_unlock(&cur->lock);
+
                        if (prev)
                                prev->next = node->next;
                        else
@@ -242,6 +269,7 @@ static struct cg_proc_stat *prune_proc_stat_list(struct cg_proc_stat *node)
 
                        free_proc_stat_node(cur);
                } else {
+next:
                        if (!first)
                                first = node;
                        prev = node;
@@ -289,8 +317,10 @@ static struct cg_proc_stat *find_proc_stat_node(struct cg_proc_stat_head *head,
        node = head->next;
 
        do {
-               if (strcmp(cg, node->cg) == 0)
+               if (strcmp(cg, node->cg) == 0) {
+                       pthread_mutex_lock(&node->lock);
                        goto out;
+               }
        } while ((node = node->next));
 
        node = NULL;
@@ -318,8 +348,6 @@ static struct cg_proc_stat *find_or_create_proc_stat_node(struct cpuacct_usage *
                lxcfs_debug("New stat node (%d) for %s\n", cpu_count, cg);
        }
 
-       pthread_mutex_lock(&node->lock);
-
        /*
         * If additional CPUs on the host have been enabled, CPU usage counter
         * arrays have to be expanded.
index 9ac040b2f55847784ff1320f41e73128730833f5..23e0b43546caf4c638a54e0a7322241f03d5d7f3 100644 (file)
@@ -24,6 +24,7 @@
 #include <sys/mman.h>
 #include <sys/mount.h>
 #include <sys/param.h>
+#include <sys/personality.h>
 #include <sys/socket.h>
 #include <sys/syscall.h>
 #include <sys/sysinfo.h>
@@ -1505,6 +1506,46 @@ static int proc_slabinfo_read(char *buf, size_t size, off_t offset,
        return total_len;
 }
 
+static int proc_read_with_personality(int (*do_proc_read)(char *, size_t, off_t,
+                            struct fuse_file_info *), char *buf, size_t size, off_t offset,
+                            struct fuse_file_info *fi)
+{
+       struct fuse_context *fc = fuse_get_context();
+       __u32 host_personality = liblxcfs_personality(), caller_personality;
+       bool change_personality;
+       int ret, read_ret;
+
+       if (get_task_personality(fc->pid, &caller_personality) < 0)
+               return log_error(0, "Failed to get caller process (pid: %d) personality", fc->pid);
+
+       /* do we need to change thread personality? */
+       change_personality = host_personality != caller_personality;
+
+       if (change_personality) {
+               ret = personality(caller_personality);
+               if (ret == -1)
+                       return log_error(0, "Call to personality(%d) failed: %s\n",
+                               caller_personality, strerror(errno));
+
+               lxcfs_debug("task (tid: %d) personality was changed %d -> %d\n",
+                               (int)syscall(SYS_gettid), ret, caller_personality);
+       }
+
+       read_ret = do_proc_read(buf, size, offset, fi);
+
+       if (change_personality) {
+               ret = personality(host_personality);
+               if (ret == -1)
+                       return log_error(0, "Call to personality(%d) failed: %s\n",
+                               host_personality, strerror(errno));
+
+               lxcfs_debug("task (tid: %d) personality was restored %d -> %d\n",
+                               (int)syscall(SYS_gettid), ret, host_personality);
+       }
+
+       return read_ret;
+}
+
 __lxcfs_fuse_ops int proc_read(const char *path, char *buf, size_t size,
                               off_t offset, struct fuse_file_info *fi)
 {
@@ -1519,7 +1560,7 @@ __lxcfs_fuse_ops int proc_read(const char *path, char *buf, size_t size,
                                                  buf, size, offset, f);
        case LXC_TYPE_PROC_CPUINFO:
                if (liblxcfs_functional())
-                       return proc_cpuinfo_read(buf, size, offset, fi);
+                       return proc_read_with_personality(&proc_cpuinfo_read, buf, size, offset, fi);
 
                return read_file_fuse_with_offset(LXC_TYPE_PROC_CPUINFO_PATH,
                                                  buf, size, offset, f);
index 926760df5a3bf9e10e291a4010d0fddba9cac816..ab665f74f6971ed2c03ab18be9995e2f565dffb7 100644 (file)
@@ -529,6 +529,29 @@ int safe_uint64(const char *numstr, uint64_t *converted, int base)
        return 0;
 }
 
+int safe_uint32(const char *numstr, uint32_t *converted, int base)
+{
+       char *err = NULL;
+       unsigned long uli;
+
+       while (isspace(*numstr))
+               numstr++;
+
+       if (*numstr == '-')
+               return -EINVAL;
+
+       errno = 0;
+       uli = strtoul(numstr, &err, base);
+       if (errno == ERANGE && uli == UINT32_MAX)
+               return -ERANGE;
+
+       if (err == numstr || *err != '\0')
+               return -EINVAL;
+
+       *converted = (uint32_t)uli;
+       return 0;
+}
+
 static int char_left_gc(const char *buffer, size_t len)
 {
        size_t i;
@@ -642,3 +665,29 @@ DIR *opendir_flags(const char *path, int flags)
 
        return dirp;
 }
+
+int get_task_personality(pid_t pid, __u32 *personality)
+{
+       __do_close int fd = -EBADF;
+       int ret = -1;
+       char path[STRLITERALLEN("/proc//personality") + INTTYPE_TO_STRLEN(pid_t) + 1];
+       /* seq_printf(m, "%08x\n", task->personality); */
+       char buf[8 + 1];
+
+       ret = strnprintf(path, sizeof(path), "/proc/%d/personality", pid);
+       if (ret < 0)
+               return -1;
+
+       fd = open(path, O_RDONLY | O_CLOEXEC);
+       if (fd < 0)
+               return -1;
+
+       ret = read_nointr(fd, buf, sizeof(buf) - 1);
+       if (ret >= 0) {
+               buf[ret] = '\0';
+               if (safe_uint32(buf, personality, 16) < 0)
+                       return log_error(-1, "Failed to convert personality %s", buf);
+       }
+
+       return ret;
+}
index eb01aca2f780db335634958a3e97e13c6478d9e5..7ed021a92891ecc927e211fae72e3f53d8655479 100644 (file)
@@ -62,6 +62,7 @@ extern FILE *fdopen_cached(int fd, const char *mode, void **caller_freed_buffer)
 extern DIR *opendir_flags(const char *path, int oflags);
 extern ssize_t write_nointr(int fd, const void *buf, size_t count);
 extern int safe_uint64(const char *numstr, uint64_t *converted, int base);
+extern int safe_uint32(const char *numstr, uint32_t *converted, int base);
 extern char *trim_whitespace_in_place(char *buffer);
 
 static inline bool file_exists(const char *f)
@@ -75,4 +76,7 @@ static inline bool file_exists(const char *f)
 #define PROTECT_OPEN (PROTECT_OPEN_WITH_TRAILING_SYMLINKS | O_NOFOLLOW)
 extern char *read_file_at(int dfd, const char *fnam, unsigned int o_flags);
 
+extern int get_task_personality(pid_t pid, __u32 *personality);
+extern int get_host_personality(__u32 *personality);
+
 #endif /* __LXCFS_UTILS_H */