diff --git a/src/bindings.c b/src/bindings.c index 061a6102..9b00997c 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -53,6 +53,7 @@ static bool has_versioned_opts; static bool memory_is_cgroupv2; static __u32 host_personality; static char runtime_path[PATH_MAX] = DEFAULT_RUNTIME_PATH; +static char force_render_cgroup[PATH_MAX] = ""; static volatile sig_atomic_t reload_successful; @@ -917,6 +918,18 @@ bool set_runtime_path(const char* new_path) } } +void set_force_render_cgroup(const char* new_path) +{ + if (new_path && strlen(new_path) < PATH_MAX) { + if (new_path[0]) { + strlcpy(force_render_cgroup, new_path, sizeof(force_render_cgroup)); + lxcfs_info("Using force render cgroup %s", force_render_cgroup); + } + } else { + lxcfs_error("%s\n", "Failed to overwrite the force render cgroup"); + } +} + void lxcfslib_init(void) { __do_close int init_ns = -EBADF, root_fd = -EBADF, @@ -1043,6 +1056,9 @@ void *lxcfs_fuse_init(struct fuse_conn_info *conn, void *data) if (opts && opts->version >= 2) { set_runtime_path(opts->runtime_path); } + if (opts && opts->version >= 5) { + set_force_render_cgroup(opts->force_render_cgroup); + } /* initialize the library */ lxcfslib_init(); diff --git a/src/bindings.h b/src/bindings.h index f65e42dc..be23ed35 100644 --- a/src/bindings.h +++ b/src/bindings.h @@ -146,6 +146,7 @@ struct lxcfs_opts { char runtime_path[PATH_MAX]; bool zswap_off; bool psi_poll_on; + char force_render_cgroup[PATH_MAX]; }; typedef enum lxcfs_opt_t { diff --git a/src/lxcfs.c b/src/lxcfs.c index af14e3bf..ca1111e7 100644 --- a/src/lxcfs.c +++ b/src/lxcfs.c @@ -37,6 +37,7 @@ void *dlopen_handle; static char runtime_path[PATH_MAX] = DEFAULT_RUNTIME_PATH; +static char force_render_cgroup[PATH_MAX] = ""; /* Functions to keep track of number of threads using the library */ @@ -926,6 +927,7 @@ static void usage(void) lxcfs_info(" --enable-cgroup Enable cgroup emulation code"); lxcfs_info(" --runtime-dir=DIR Path to use as the runtime directory."); lxcfs_info(" Default is %s", DEFAULT_RUNTIME_PATH); + lxcfs_info(" --force-render-cgroup Make procfs/sysfs render in view of cgroup in args"); exit(EXIT_FAILURE); } @@ -977,6 +979,7 @@ static const struct option long_options[] = { {"enable-pidfd", no_argument, 0, 0 }, {"enable-cgroup", no_argument, 0, 0 }, {"enable-psi-poll", no_argument, 0, 0 }, + {"force-render-cgroup", required_argument, 0, 0 }, {"pidfile", required_argument, 0, 'p' }, {"runtime-dir", required_argument, 0, 0 }, @@ -1040,6 +1043,7 @@ int main(int argc, char *argv[]) char *const *new_argv; struct lxcfs_opts *opts; char *runtime_path_arg = NULL; + char *force_render_cgroup_arg = NULL; opts = malloc(sizeof(struct lxcfs_opts)); if (opts == NULL) { @@ -1052,7 +1056,7 @@ int main(int argc, char *argv[]) opts->use_pidfd = false; opts->use_cfs = false; opts->psi_poll_on = false; - opts->version = 4; + opts->version = 5; while ((c = getopt_long(argc, argv, "dulfhvso:p:", long_options, &idx)) != -1) { switch (c) { @@ -1067,6 +1071,8 @@ int main(int argc, char *argv[]) opts->psi_poll_on = true; else if (strcmp(long_options[idx].name, "runtime-dir") == 0) runtime_path_arg = optarg; + else if (strcmp(long_options[idx].name, "force-render-cgroup") == 0) + force_render_cgroup_arg = optarg; else usage(); break; @@ -1127,6 +1133,11 @@ int main(int argc, char *argv[]) lxcfs_info("runtime path set to %s", runtime_path); } strlcpy(opts->runtime_path, runtime_path, sizeof(opts->runtime_path)); + if (force_render_cgroup_arg) { + strlcpy(force_render_cgroup, force_render_cgroup_arg, sizeof(force_render_cgroup)); + lxcfs_info("force render cgroup set to %s", force_render_cgroup); + } + strlcpy(opts->force_render_cgroup, force_render_cgroup, sizeof(opts->force_render_cgroup)); fuse_argv[fuse_argc++] = argv[0]; if (debug) diff --git a/src/proc_cpuview.c b/src/proc_cpuview.c index 0063fd58..1b0f640f 100644 --- a/src/proc_cpuview.c +++ b/src/proc_cpuview.c @@ -977,18 +977,23 @@ int proc_cpuinfo_read(char *buf, size_t size, off_t offset, return total_len; } - pid_t initpid = lookup_initpid_in_store(fc->pid); - if (initpid <= 1 || is_shared_pidns(initpid)) - initpid = fc->pid; - - cg = get_pid_cgroup(initpid, "cpuset"); - if (!cg) - return read_file_fuse("proc/cpuinfo", buf, size, d); - prune_init_slice(cg); - cpu_cg = get_pid_cgroup(initpid, "cpu"); - if (!cpu_cg) - return read_file_fuse("proc/cpuinfo", buf, size, d); - prune_init_slice(cpu_cg); + if (opts && opts->force_render_cgroup[0]) { + cg = strdup(opts->force_render_cgroup); + cpu_cg = strdup(opts->force_render_cgroup); + } else { + pid_t initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 1 || is_shared_pidns(initpid)) + initpid = fc->pid; + + cg = get_pid_cgroup(initpid, "cpuset"); + if (!cg) + return read_file_fuse("proc/cpuinfo", buf, size, d); + prune_init_slice(cg); + cpu_cg = get_pid_cgroup(initpid, "cpu"); + if (!cpu_cg) + return read_file_fuse("proc/cpuinfo", buf, size, d); + prune_init_slice(cpu_cg); + } cpuset = get_cpuset(cg); if (!cpuset) return 0; diff --git a/src/proc_fuse.c b/src/proc_fuse.c index 8ed3be29..47a7f336 100644 --- a/src/proc_fuse.c +++ b/src/proc_fuse.c @@ -497,6 +497,7 @@ static int proc_swaps_read(char *buf, size_t size, off_t offset, __do_free char *cgroup = NULL, *memusage_str = NULL, *memswusage_str = NULL, *memswpriority_str = NULL; struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = (struct lxcfs_opts *)fc->private_data; bool wants_swap = lxcfs_has_opt(fuse_get_context()->private_data, LXCFS_SWAP_ON); struct file_info *d = INTTYPE_TO_PTR(fi->fh); uint64_t memlimit = 0, memusage = 0, @@ -527,14 +528,18 @@ static int proc_swaps_read(char *buf, size_t size, off_t offset, return total_len; } - pid_t initpid = lookup_initpid_in_store(fc->pid); - if (initpid <= 1 || is_shared_pidns(initpid)) - initpid = fc->pid; + if (opts && opts->force_render_cgroup[0]) { + cgroup = strdup(opts->force_render_cgroup); + } else { + pid_t initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 1 || is_shared_pidns(initpid)) + initpid = fc->pid; - cgroup = get_pid_cgroup(initpid, "memory"); - if (!cgroup) - return read_file_fuse("/proc/swaps", buf, size, d); - prune_init_slice(cgroup); + cgroup = get_pid_cgroup(initpid, "memory"); + if (!cgroup) + return read_file_fuse("/proc/swaps", buf, size, d); + prune_init_slice(cgroup); + } ret = get_min_memlimit(cgroup, false, &memlimit); if (ret < 0) @@ -655,6 +660,7 @@ static int proc_diskstats_read(char *buf, size_t size, off_t offset, __do_free void *fopen_cache = NULL; __do_fclose FILE *f = NULL; struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = (struct lxcfs_opts *)fc->private_data; struct file_info *d = INTTYPE_TO_PTR(fi->fh); struct lxcfs_diskstats stats = {}; /* helper fields */ @@ -682,14 +688,18 @@ static int proc_diskstats_read(char *buf, size_t size, off_t offset, return total_len; } - pid_t initpid = lookup_initpid_in_store(fc->pid); - if (initpid <= 1 || is_shared_pidns(initpid)) - initpid = fc->pid; + if (opts && opts->force_render_cgroup[0]) { + cg = strdup(opts->force_render_cgroup); + } else { + pid_t initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 1 || is_shared_pidns(initpid)) + initpid = fc->pid; - cg = get_pid_cgroup(initpid, "blkio"); - if (!cg) - return read_file_fuse("/proc/diskstats", buf, size, d); - prune_init_slice(cg); + cg = get_pid_cgroup(initpid, "blkio"); + if (!cg) + return read_file_fuse("/proc/diskstats", buf, size, d); + prune_init_slice(cg); + } ret = cgroup_ops->get_io_serviced(cgroup_ops, cg, &io_serviced_str); if (ret < 0) { @@ -859,18 +869,24 @@ static inline void iwashere(void) */ static double get_reaper_busy(pid_t task) { + struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = (struct lxcfs_opts *)fc->private_data; __do_free char *cgroup = NULL, *usage_str = NULL; uint64_t usage = 0; pid_t initpid; - initpid = lookup_initpid_in_store(task); - if (initpid <= 0) - return 0; + if (opts && opts->force_render_cgroup[0]) { + cgroup = strdup(opts->force_render_cgroup); + } else { + initpid = lookup_initpid_in_store(task); + if (initpid <= 0) + return 0; - cgroup = get_pid_cgroup(initpid, "cpuacct"); - if (!cgroup) - return 0; - prune_init_slice(cgroup); + cgroup = get_pid_cgroup(initpid, "cpuacct"); + if (!cgroup) + return 0; + prune_init_slice(cgroup); + } if (!cgroup_ops->get(cgroup_ops, "cpuacct", cgroup, "cpuacct.usage", &usage_str)) return 0; @@ -1084,26 +1100,31 @@ static int proc_stat_read(char *buf, size_t size, off_t offset, return total_len; } - pid_t initpid = lookup_initpid_in_store(fc->pid); - if (initpid <= 1 || is_shared_pidns(initpid)) - initpid = fc->pid; + if (opts && opts->force_render_cgroup[0]) { + cg = strdup(opts->force_render_cgroup); + cpu_cg = strdup(opts->force_render_cgroup); + } else { + pid_t initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 1 || is_shared_pidns(initpid)) + initpid = fc->pid; - /* - * when container run with host pid namespace initpid == 1, cgroup will "/" - * we should return host os's /proc contents. - * in some case cpuacct_usage.all in "/" will larger then /proc/stat - */ - if (initpid == 1) - return read_file_fuse("/proc/stat", buf, size, d); - - cg = get_pid_cgroup(initpid, "cpuset"); - if (!cg) - return read_file_fuse("/proc/stat", buf, size, d); - prune_init_slice(cg); - cpu_cg = get_pid_cgroup(initpid, "cpu"); - if (!cpu_cg) - return read_file_fuse("/proc/stat", buf, size, d); - prune_init_slice(cpu_cg); + /* + * when container run with host pid namespace initpid == 1, cgroup will "/" + * we should return host os's /proc contents. + * in some case cpuacct_usage.all in "/" will larger then /proc/stat + */ + if (initpid == 1) + return read_file_fuse("/proc/stat", buf, size, d); + + cg = get_pid_cgroup(initpid, "cpuset"); + if (!cg) + return read_file_fuse("/proc/stat", buf, size, d); + prune_init_slice(cg); + cpu_cg = get_pid_cgroup(initpid, "cpu"); + if (!cpu_cg) + return read_file_fuse("/proc/stat", buf, size, d); + prune_init_slice(cpu_cg); + } cpuset = get_cpuset(cg); if (!cpuset) return 0; @@ -1398,6 +1419,7 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, __do_free void *fopen_cache = NULL; __do_fclose FILE *f = NULL; struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = (struct lxcfs_opts *)fc->private_data; bool wants_swap = lxcfs_has_opt(fuse_get_context()->private_data, LXCFS_SWAP_ON); bool wants_zswap = lxcfs_has_opt(fuse_get_context()->private_data, LXCFS_ZSWAP_ON); struct file_info *d = INTTYPE_TO_PTR(fi->fh); @@ -1426,15 +1448,19 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset, return total_len; } - pid_t initpid = lookup_initpid_in_store(fc->pid); - if (initpid <= 1 || is_shared_pidns(initpid)) - initpid = fc->pid; + if (opts && opts->force_render_cgroup[0]) { + cgroup = strdup(opts->force_render_cgroup); + } else { + pid_t initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 1 || is_shared_pidns(initpid)) + initpid = fc->pid; - cgroup = get_pid_cgroup(initpid, "memory"); - if (!cgroup) - return read_file_fuse("/proc/meminfo", buf, size, d); + cgroup = get_pid_cgroup(initpid, "memory"); + if (!cgroup) + return read_file_fuse("/proc/meminfo", buf, size, d); - prune_init_slice(cgroup); + prune_init_slice(cgroup); + } /* memory limits */ ret = cgroup_ops->get_memory_current(cgroup_ops, cgroup, &memusage_str); @@ -1637,6 +1663,7 @@ static int proc_slabinfo_read(char *buf, size_t size, off_t offset, __do_fclose FILE *f = NULL; __do_close int fd = -EBADF; struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = (struct lxcfs_opts *)fc->private_data; struct file_info *d = INTTYPE_TO_PTR(fi->fh); size_t linelen = 0, total_len = 0; char *cache = d->buf; @@ -1659,15 +1686,19 @@ static int proc_slabinfo_read(char *buf, size_t size, off_t offset, return total_len; } - initpid = lookup_initpid_in_store(fc->pid); - if (initpid <= 1 || is_shared_pidns(initpid)) - initpid = fc->pid; + if (opts && opts->force_render_cgroup[0]) { + cgroup = strdup(opts->force_render_cgroup); + } else { + initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 1 || is_shared_pidns(initpid)) + initpid = fc->pid; - cgroup = get_pid_cgroup(initpid, "memory"); - if (!cgroup) - return read_file_fuse("/proc/slabinfo", buf, size, d); + cgroup = get_pid_cgroup(initpid, "memory"); + if (!cgroup) + return read_file_fuse("/proc/slabinfo", buf, size, d); - prune_init_slice(cgroup); + prune_init_slice(cgroup); + } fd = cgroup_ops->get_memory_slabinfo_fd(cgroup_ops, cgroup); if (fd < 0) @@ -1706,6 +1737,7 @@ static int proc_pressure_read(char *buf, size_t size, off_t offset, __do_fclose FILE *f = NULL; __do_close int fd = -EBADF; struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = (struct lxcfs_opts *)fc->private_data; struct file_info *d = INTTYPE_TO_PTR(fi->fh); size_t linelen = 0, total_len = 0; char *cache = d->buf; @@ -1751,15 +1783,19 @@ static int proc_pressure_read(char *buf, size_t size, off_t offset, return -EINVAL; } - initpid = lookup_initpid_in_store(fc->pid); - if (initpid <= 1 || is_shared_pidns(initpid)) - initpid = fc->pid; + if (opts && opts->force_render_cgroup[0]) { + cgroup = strdup(opts->force_render_cgroup); + } else { + initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 1 || is_shared_pidns(initpid)) + initpid = fc->pid; - cgroup = get_pid_cgroup(initpid, controller); - if (!cgroup) - return read_file_fuse(fallback_path, buf, size, d); + cgroup = get_pid_cgroup(initpid, controller); + if (!cgroup) + return read_file_fuse(fallback_path, buf, size, d); - prune_init_slice(cgroup); + prune_init_slice(cgroup); + } fd = get_pressure_fd(cgroup_ops, cgroup); if (fd < 0) @@ -1938,6 +1974,7 @@ static int proc_psi_trigger_write(const char *path, const char *buf, size_t size off_t offset, struct fuse_file_info *fi) { struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = fc->private_data; bool psi_virtualization_enabled = lxcfs_has_opt(fc->private_data, LXCFS_PSI_POLL_ON); struct file_info *f = INTTYPE_TO_PTR(fi->fh); __do_free psi_trigger_t *t = NULL; @@ -2021,15 +2058,19 @@ static int proc_psi_trigger_write(const char *path, const char *buf, size_t size return -EINVAL; } - initpid = lookup_initpid_in_store(fc->pid); - if (initpid <= 1 || is_shared_pidns(initpid)) - initpid = fc->pid; + if (opts && opts->force_render_cgroup[0]) { + cgroup = strdup(opts->force_render_cgroup); + } else { + initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 1 || is_shared_pidns(initpid)) + initpid = fc->pid; - cgroup = get_pid_cgroup(initpid, controller); - if (!cgroup) - return -EIO; + cgroup = get_pid_cgroup(initpid, controller); + if (!cgroup) + return -EIO; - prune_init_slice(cgroup); + prune_init_slice(cgroup); + } fd = get_pressure_fd(cgroup_ops, cgroup); if (fd < 0) diff --git a/src/proc_loadavg.c b/src/proc_loadavg.c index fa33193c..3acff805 100644 --- a/src/proc_loadavg.c +++ b/src/proc_loadavg.c @@ -191,6 +191,7 @@ int proc_loadavg_read(char *buf, size_t size, off_t offset, { __do_free char *cg = NULL; struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = (struct lxcfs_opts *)fc->private_data; struct file_info *d = INTTYPE_TO_PTR(fi->fh); pid_t initpid; ssize_t total_len = 0; @@ -217,15 +218,19 @@ int proc_loadavg_read(char *buf, size_t size, off_t offset, if (!loadavg) return read_file_fuse("/proc/loadavg", buf, size, d); - initpid = lookup_initpid_in_store(fc->pid); - if (initpid <= 1 || is_shared_pidns(initpid)) - initpid = fc->pid; + if (opts && opts->force_render_cgroup[0]) { + cg = strdup(opts->force_render_cgroup); + } else { + initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 1 || is_shared_pidns(initpid)) + initpid = fc->pid; - cg = get_pid_cgroup(initpid, "cpu"); - if (!cg) - return read_file_fuse("/proc/loadavg", buf, size, d); + cg = get_pid_cgroup(initpid, "cpu"); + if (!cg) + return read_file_fuse("/proc/loadavg", buf, size, d); - prune_init_slice(cg); + prune_init_slice(cg); + } hash = calc_hash(cg) % LOAD_SIZE; n = locate_node(cg, hash); diff --git a/src/sysfs_fuse.c b/src/sysfs_fuse.c index bf75ba99..e2b0ec8a 100644 --- a/src/sysfs_fuse.c +++ b/src/sysfs_fuse.c @@ -79,6 +79,7 @@ static int sys_devices_system_cpu_online_read(char *buf, size_t size, { __do_free char *cg = NULL, *cpu_cg = NULL; struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = (struct lxcfs_opts *)fc->private_data; struct file_info *d = INTTYPE_TO_PTR(fi->fh); char *cache = d->buf; pid_t initpid; @@ -100,18 +101,23 @@ static int sys_devices_system_cpu_online_read(char *buf, size_t size, return total_len; } - initpid = lookup_initpid_in_store(fc->pid); - if (initpid <= 1 || is_shared_pidns(initpid)) - initpid = fc->pid; - - cg = get_pid_cgroup(initpid, "cpuset"); - if (!cg) - return read_file_fuse("/sys/devices/system/cpu/online", buf, size, d); - prune_init_slice(cg); - cpu_cg = get_pid_cgroup(initpid, "cpu"); - if (!cpu_cg) - return read_file_fuse("/sys/devices/system/cpu/online", buf, size, d); - prune_init_slice(cpu_cg); + if (opts && opts->force_render_cgroup[0]) { + cg = strdup(opts->force_render_cgroup); + cpu_cg = strdup(opts->force_render_cgroup); + } else { + initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 1 || is_shared_pidns(initpid)) + initpid = fc->pid; + + cg = get_pid_cgroup(initpid, "cpuset"); + if (!cg) + return read_file_fuse("/sys/devices/system/cpu/online", buf, size, d); + prune_init_slice(cg); + cpu_cg = get_pid_cgroup(initpid, "cpu"); + if (!cpu_cg) + return read_file_fuse("/sys/devices/system/cpu/online", buf, size, d); + prune_init_slice(cpu_cg); + } total_len = do_cpuset_read(cg, cpu_cg, d->buf, d->buflen); d->size = (int)total_len; @@ -129,22 +135,28 @@ static int sys_devices_system_cpu_online_getsize(const char *path) { __do_free char *cg = NULL, *cpu_cg = NULL; struct fuse_context *fc = fuse_get_context(); + struct lxcfs_opts *opts = (struct lxcfs_opts *)fc->private_data; pid_t initpid; char buf[BUF_RESERVE_SIZE]; int buflen = sizeof(buf); - initpid = lookup_initpid_in_store(fc->pid); - if (initpid <= 1 || is_shared_pidns(initpid)) - initpid = fc->pid; - - cg = get_pid_cgroup(initpid, "cpuset"); - if (!cg) - return get_sysfile_size(path); - cpu_cg = get_pid_cgroup(initpid, "cpu"); - if (!cpu_cg) - return get_sysfile_size(path); - prune_init_slice(cg); - prune_init_slice(cpu_cg); + if (opts && opts->force_render_cgroup[0]) { + cg = strdup(opts->force_render_cgroup); + cpu_cg = strdup(opts->force_render_cgroup); + } else { + initpid = lookup_initpid_in_store(fc->pid); + if (initpid <= 1 || is_shared_pidns(initpid)) + initpid = fc->pid; + + cg = get_pid_cgroup(initpid, "cpuset"); + if (!cg) + return get_sysfile_size(path); + cpu_cg = get_pid_cgroup(initpid, "cpu"); + if (!cpu_cg) + return get_sysfile_size(path); + prune_init_slice(cg); + prune_init_slice(cpu_cg); + } return do_cpuset_read(cg, cpu_cg, buf, buflen); }