[lxc-devel] [lxcfs/master] Support /sys/devices/system/cpu/online

wavezhang on Github lxc-bot at linuxcontainers.org
Fri Mar 22 07:46:59 UTC 2019


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 438 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20190322/22bf290f/attachment.bin>
-------------- next part --------------
From 6ac2c98a13ed750f3b46eab7f22626e4ba3d5da4 Mon Sep 17 00:00:00 2001
From: Sam <baoyafei at gmail.com>
Date: Fri, 22 Mar 2019 15:28:29 +0800
Subject: [PATCH 1/2] support /sys/devices/system/cpu/online

---
 bindings.c | 273 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 bindings.h |  11 +++
 lxcfs.c    | 171 +++++++++++++++++++++++++++++++++
 3 files changed, 455 insertions(+)

diff --git a/bindings.c b/bindings.c
index 049418c..c1dbaa6 100644
--- a/bindings.c
+++ b/bindings.c
@@ -67,6 +67,10 @@ enum {
 	LXC_TYPE_PROC_DISKSTATS,
 	LXC_TYPE_PROC_SWAPS,
 	LXC_TYPE_PROC_LOADAVG,
+	LXC_TYPE_SYS_DEVICES,
+	LXC_TYPE_SYS_DEVICES_SYSTEM,
+	LXC_TYPE_SYS_DEVICES_SYSTEM_CPU,
+	LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE,
 };
 
 struct file_info {
@@ -5874,6 +5878,275 @@ int proc_read(const char *path, char *buf, size_t size, off_t offset,
 	}
 }
 
+static int sys_devices_system_cpu_read(char *buf, size_t size, off_t offset,
+		struct fuse_file_info *fi)
+{
+	struct fuse_context *fc = fuse_get_context();
+	struct file_info *d = (struct file_info *)fi->fh;
+	char *cache = d->buf;
+	ssize_t total_len = 0;
+	if (offset){
+		if (!d->cached)
+			return 0;
+		if (offset > d->size)
+			return -EINVAL;
+		int left = d->size - offset;
+		total_len = left > size ? size: left;
+		memcpy(buf, cache + offset, total_len);
+		return total_len;
+	}
+
+	total_len = snprintf(d->buf, d->buflen, "0-1\n");
+	if (total_len < 0 || total_len >=  d->buflen){
+		lxcfs_error("%s\n", "failed to write to cache");
+		return 0;
+	}
+
+	d->size = (int)total_len;
+	d->cached = 1;
+
+	if (total_len > size) total_len = size;
+
+	memcpy(buf, d->buf, total_len);
+	return total_len;
+}
+
+static int sys_devices_system_cpu_online_read(char *buf, size_t size, off_t offset,
+		struct fuse_file_info *fi)
+{
+	struct fuse_context *fc = fuse_get_context();
+	struct file_info *d = (struct file_info *)fi->fh;
+	char *cache = d->buf;
+	char *cg;
+	char *cpuset = NULL;
+	bool use_view;
+
+        int max_cpus = 0;
+	ssize_t total_len = 0;
+	if (offset){
+		if (!d->cached)
+			return 0;
+		if (offset > d->size)
+			return -EINVAL;
+		int left = d->size - offset;
+		total_len = left > size ? size: left;
+		memcpy(buf, cache + offset, total_len);
+		return total_len;
+	}
+	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("/sys/devices/system/cpu/online", buf, size, d);
+	prune_init_slice(cg);
+
+	cpuset = get_cpuset(cg);
+	if (!cpuset)
+		goto err;
+
+	use_view = use_cpuview(cg);
+
+	if (use_view)
+		max_cpus = max_cpu_count(cg);
+
+
+	if (max_cpus == 0)
+		return read_file("/sys/devices/system/cpu/online", buf, size, d);
+	if (max_cpus > 1)
+		total_len = snprintf(d->buf, d->buflen, "0-%d\n", max_cpus - 1);
+	else
+		total_len = snprintf(d->buf, d->buflen, "0\n");
+	if (total_len < 0 || total_len >=  d->buflen){
+		lxcfs_error("%s\n", "failed to write to cache");
+		return 0;
+	}
+
+	d->size = (int)total_len;
+	d->cached = 1;
+
+	if (total_len > size) total_len = size;
+
+	memcpy(buf, d->buf, total_len);
+err:
+	free(cpuset);
+	free(cg);
+	return total_len;
+}
+
+static off_t get_sysfile_size(const char *which)
+{
+	FILE *f = fopen(which, "r");
+	char *line = NULL;
+	size_t len = 0;
+	ssize_t sz, answer = 0;
+	if (!f)
+		return 0;
+
+	while ((sz = getline(&line, &len, f)) != -1)
+		answer += sz;
+	fclose (f);
+	free(line);
+
+	return answer;
+}
+
+int sys_getattr(const char *path, struct stat *sb)
+{
+	struct timespec now;
+
+	memset(sb, 0, sizeof(struct stat));
+	if (clock_gettime(CLOCK_REALTIME, &now) < 0)
+		return -EINVAL;
+	sb->st_uid = sb->st_gid = 0;
+	sb->st_atim = sb->st_mtim = sb->st_ctim = now;
+	if (strcmp(path, "/sys") == 0) {
+		sb->st_mode = S_IFDIR | 00555;
+		sb->st_nlink = 2;
+		return 0;
+	}
+	if (strcmp(path, "/sys/devices") == 0) {
+		sb->st_mode = S_IFDIR | 00555;
+		sb->st_nlink = 2;
+		return 0;
+	}
+	if (strcmp(path, "/sys/devices/system") == 0) {
+		sb->st_mode = S_IFDIR | 00555;
+		sb->st_nlink = 2;
+		return 0;
+	}
+	if (strcmp(path, "/sys/devices/system/cpu") == 0) {
+		sb->st_mode = S_IFDIR | 00555;
+		sb->st_nlink = 2;
+		return 0;
+	}
+	if (strcmp(path, "/sys/devices/system/cpu/online") == 0) {
+		sb->st_size = 0;
+		sb->st_mode = S_IFREG | 00444;
+		sb->st_nlink = 1;
+		return 0;
+	}
+
+	return -ENOENT;
+}
+
+int sys_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
+		struct fuse_file_info *fi)
+{
+	if (strcmp(path, "/sys") == 0) {
+		if (filler(buf, ".", NULL, 0) != 0 ||
+		    filler(buf, "..", NULL, 0) != 0 ||
+		    filler(buf, "devices", NULL, 0) != 0)
+			return -ENOENT;
+		return 0;
+	}
+	if (strcmp(path, "/sys/devices") == 0) {
+		if (filler(buf, ".", NULL, 0) != 0 ||
+		    filler(buf, "..", NULL, 0) != 0 ||
+		    filler(buf, "system", NULL, 0) != 0)
+			return -ENOENT;
+		return 0;
+	}
+	if (strcmp(path, "/sys/devices/system") == 0) {
+		if (filler(buf, ".", NULL, 0) != 0 ||
+		    filler(buf, "..", NULL, 0) != 0 ||
+		    filler(buf, "cpu", NULL, 0) != 0)
+			return -ENOENT;
+		return 0;
+	}
+	if (strcmp(path, "/sys/devices/system/cpu") == 0) {
+		if (filler(buf, ".", NULL, 0) != 0 ||
+		    filler(buf, "..", NULL, 0) != 0 ||
+		    filler(buf, "online", NULL, 0) != 0)
+			return -ENOENT;
+		return 0;
+	}
+
+	return 0;
+}
+
+int sys_open(const char *path, struct fuse_file_info *fi)
+{
+	int type = -1;
+	struct file_info *info;
+
+	if (strcmp(path, "/sys/devices") == 0)
+		type = LXC_TYPE_SYS_DEVICES;
+	if (strcmp(path, "/sys/devices/system") == 0)
+		type = LXC_TYPE_SYS_DEVICES_SYSTEM;
+	if (strcmp(path, "/sys/devices/system/cpu") == 0)
+		type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU;
+	if (strcmp(path, "/sys/devices/system/cpu/online") == 0)
+		type = LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE;
+	if (type == -1)
+		return -ENOENT;
+
+	info = malloc(sizeof(*info));
+	if (!info)
+		return -ENOMEM;
+
+	memset(info, 0, sizeof(*info));
+	info->type = type;
+
+	info->buflen = get_sysfile_size(path) + BUF_RESERVE_SIZE;
+	do {
+		info->buf = malloc(info->buflen);
+	} while (!info->buf);
+	memset(info->buf, 0, info->buflen);
+	/* set actual size to buffer size */
+	info->size = info->buflen;
+
+	fi->fh = (unsigned long)info;
+	return 0;
+}
+
+int sys_access(const char *path, int mask)
+{
+	if (strcmp(path, "/sys") == 0 && access(path, R_OK) == 0)
+		return 0;
+	if (strcmp(path, "/sys/devices") == 0 && access(path, R_OK) == 0)
+		return 0;
+	if (strcmp(path, "/sys/devices/system") == 0 && access(path, R_OK) == 0)
+		return 0;
+	if (strcmp(path, "/sys/devices/system/cpu") == 0 && access(path, R_OK) == 0)
+		return 0;
+	/* these are all read-only */
+	if ((mask & ~R_OK) != 0)
+		return -EACCES;
+	return 0;
+}
+
+int sys_release(const char *path, struct fuse_file_info *fi)
+{
+	do_release_file_info(fi);
+	return 0;
+}
+
+int sys_releasedir(const char *path, struct fuse_file_info *fi)
+{
+	do_release_file_info(fi);
+	return 0;
+}
+
+int sys_read(const char *path, char *buf, size_t size, off_t offset,
+		struct fuse_file_info *fi)
+{
+	struct file_info *f = (struct file_info *) fi->fh;
+
+	switch (f->type) {
+	case LXC_TYPE_SYS_DEVICES:
+		return sys_devices_read(buf, size, offset, fi);
+	case LXC_TYPE_SYS_DEVICES_SYSTEM:
+		return sys_devices_system_read(buf, size, offset, fi);
+	case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU:
+		return sys_devices_system_cpu_read(buf, size, offset, fi);
+	case LXC_TYPE_SYS_DEVICES_SYSTEM_CPU_ONLINE:
+		return sys_devices_system_cpu_online_read(buf, size, offset, fi);
+	default:
+		return -EINVAL;
+	}
+}
+
 /*
  * Functions needed to setup cgroups in the __constructor__.
  */
diff --git a/bindings.h b/bindings.h
index 20df78c..88e6915 100644
--- a/bindings.h
+++ b/bindings.h
@@ -36,6 +36,17 @@ extern int proc_open(const char *path, struct fuse_file_info *fi);
 extern int proc_read(const char *path, char *buf, size_t size, off_t offset,
 		struct fuse_file_info *fi);
 extern int proc_access(const char *path, int mask);
+
+extern int sys_getattr(const char *path, struct stat *sb);
+extern int sys_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
+		struct fuse_file_info *fi);
+extern int sys_release(const char *path, struct fuse_file_info *fi);
+extern int sys_releasedir(const char *path, struct fuse_file_info *fi);
+extern int sys_open(const char *path, struct fuse_file_info *fi);
+extern int sys_read(const char *path, char *buf, size_t size, off_t offset,
+		struct fuse_file_info *fi);
+extern int sys_access(const char *path, int mask);
+
 extern pthread_t load_daemon(int load_use);
 extern int stop_load_daemon(pthread_t pid);
 
diff --git a/lxcfs.c b/lxcfs.c
index 2247fcb..ee94b75 100644
--- a/lxcfs.c
+++ b/lxcfs.c
@@ -205,6 +205,21 @@ static int do_proc_getattr(const char *path, struct stat *sb)
 	return proc_getattr(path, sb);
 }
 
+static int do_sys_getattr(const char *path, struct stat *sb)
+{
+	int (*sys_getattr)(const char *path, struct stat *sb);
+	char *error;
+	dlerror();    /* Clear any existing error */
+	sys_getattr = (int (*)(const char *, struct stat *)) dlsym(dlopen_handle, "sys_getattr");
+	error = dlerror();
+	if (error != NULL) {
+		lxcfs_error("%s\n", error);
+		return -1;
+	}
+
+	return sys_getattr(path, sb);
+}
+
 static int do_cg_read(const char *path, char *buf, size_t size, off_t offset,
 		struct fuse_file_info *fi)
 {
@@ -241,6 +256,24 @@ static int do_proc_read(const char *path, char *buf, size_t size, off_t offset,
 	return proc_read(path, buf, size, offset, fi);
 }
 
+static int do_sys_read(const char *path, char *buf, size_t size, off_t offset,
+		struct fuse_file_info *fi)
+{
+	int (*sys_read)(const char *path, char *buf, size_t size, off_t offset,
+		struct fuse_file_info *fi);
+	char *error;
+
+	dlerror();    /* Clear any existing error */
+	sys_read = (int (*)(const char *, char *, size_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "sys_read");
+	error = dlerror();
+	if (error != NULL) {
+		lxcfs_error("%s\n", error);
+		return -1;
+	}
+
+	return sys_read(path, buf, size, offset, fi);
+}
+
 static int do_cg_write(const char *path, const char *buf, size_t size, off_t offset,
 	     struct fuse_file_info *fi)
 {
@@ -354,6 +387,25 @@ static int do_proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
 	return proc_readdir(path, buf, filler, offset, fi);
 }
 
+static int do_sys_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
+		struct fuse_file_info *fi)
+{
+	int (*sys_readdir)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset,
+		struct fuse_file_info *fi);
+	char *error;
+
+	dlerror();    /* Clear any existing error */
+	sys_readdir = (int (*)(const char *, void *, fuse_fill_dir_t, off_t, struct fuse_file_info *)) dlsym(dlopen_handle, "sys_readdir");
+	error = dlerror();
+	if (error != NULL) {
+		lxcfs_error("%s\n", error);
+		return -1;
+	}
+
+	return sys_readdir(path, buf, filler, offset, fi);
+}
+
+
 static int do_cg_open(const char *path, struct fuse_file_info *fi)
 {
 	int (*cg_open)(const char *path, struct fuse_file_info *fi);
@@ -414,6 +466,37 @@ static int do_proc_access(const char *path, int mode)
 	return proc_access(path, mode);
 }
 
+static int do_sys_open(const char *path, struct fuse_file_info *fi)
+{
+	int (*sys_open)(const char *path, struct fuse_file_info *fi);
+	char *error;
+	dlerror();    /* Clear any existing error */
+	sys_open = (int (*)(const char *path, struct fuse_file_info *fi)) dlsym(dlopen_handle, "sys_open");
+	error = dlerror();
+	if (error != NULL) {
+		lxcfs_error("%s\n", error);
+		return -1;
+	}
+
+	return sys_open(path, fi);
+}
+
+static int do_sys_access(const char *path, int mode)
+{
+	int (*sys_access)(const char *path, int mode);
+	char *error;
+	dlerror();    /* Clear any existing error */
+	sys_access = (int (*)(const char *, int mode)) dlsym(dlopen_handle, "sys_access");
+	error = dlerror();
+	if (error != NULL) {
+		lxcfs_error("%s\n", error);
+		return -1;
+	}
+
+	return sys_access(path, mode);
+}
+
+
 static int do_cg_release(const char *path, struct fuse_file_info *fi)
 {
 	int (*cg_release)(const char *path, struct fuse_file_info *fi);
@@ -444,6 +527,21 @@ static int do_proc_release(const char *path, struct fuse_file_info *fi)
 	return proc_release(path, fi);
 }
 
+static int do_sys_release(const char *path, struct fuse_file_info *fi)
+{
+	int (*sys_release)(const char *path, struct fuse_file_info *fi);
+	char *error;
+	dlerror();    /* Clear any existing error */
+	sys_release = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "sys_release");
+	error = dlerror();
+	if (error != NULL) {
+		lxcfs_error("%s\n", error);
+		return -1;
+	}
+
+	return sys_release(path, fi);
+}
+
 static int do_cg_opendir(const char *path, struct fuse_file_info *fi)
 {
 	int (*cg_opendir)(const char *path, struct fuse_file_info *fi);
@@ -474,6 +572,21 @@ static int do_cg_releasedir(const char *path, struct fuse_file_info *fi)
 	return cg_releasedir(path, fi);
 }
 
+static int do_sys_releasedir(const char *path, struct fuse_file_info *fi)
+{
+	int (*sys_releasedir)(const char *path, struct fuse_file_info *fi);
+	char *error;
+	dlerror();    /* Clear any existing error */
+	sys_releasedir = (int (*)(const char *path, struct fuse_file_info *)) dlsym(dlopen_handle, "sys_releasedir");
+	error = dlerror();
+	if (error != NULL) {
+		lxcfs_error("%s\n", error);
+		return -1;
+	}
+
+	return sys_releasedir(path, fi);
+}
+
 /*
  * FUSE ops for /
  * these just delegate to the /proc and /cgroup ops as
@@ -508,6 +621,12 @@ static int lxcfs_getattr(const char *path, struct stat *sb)
 		down_users();
 		return ret;
 	}
+	if (strncmp(path, "/sys", 4) == 0) {
+		up_users();
+		ret = do_sys_getattr(path, sb);
+		down_users();
+		return ret;
+	}
 	return -ENOENT;
 }
 
@@ -525,6 +644,9 @@ static int lxcfs_opendir(const char *path, struct fuse_file_info *fi)
 	}
 	if (strcmp(path, "/proc") == 0)
 		return 0;
+	if (strncmp(path, "/sys", 4) == 0)
+		return 0;
+
 	return -ENOENT;
 }
 
@@ -536,6 +658,7 @@ static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, of
 		if (filler(buf, ".", NULL, 0) != 0 ||
 		    filler(buf, "..", NULL, 0) != 0 ||
 		    filler(buf, "proc", NULL, 0) != 0 ||
+		    filler(buf, "sys", NULL, 0) != 0 ||
 		    filler(buf, "cgroup", NULL, 0) != 0)
 			return -ENOMEM;
 		return 0;
@@ -552,6 +675,14 @@ static int lxcfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, of
 		down_users();
 		return ret;
 	}
+
+	if (strncmp(path, "/sys", 4) == 0) {
+		up_users();
+		ret = do_sys_readdir(path, buf, filler, offset, fi);
+		down_users();
+		return ret;
+	}
+
 	return -ENOENT;
 }
 
@@ -574,6 +705,13 @@ static int lxcfs_access(const char *path, int mode)
 		down_users();
 		return ret;
 	}
+	if (strncmp(path, "/sys", 4) == 0) {
+		up_users();
+		ret = do_sys_access(path, mode);
+		down_users();
+		return ret;
+	}
+
 
 	return -EACCES;
 }
@@ -591,6 +729,13 @@ static int lxcfs_releasedir(const char *path, struct fuse_file_info *fi)
 	}
 	if (strcmp(path, "/proc") == 0)
 		return 0;
+	if (strncmp(path, "/sys", 4) == 0){
+		up_users();
+		ret = do_sys_releasedir(path, fi);
+		down_users();
+		return ret;
+	}
+
 	return -EINVAL;
 }
 
@@ -609,6 +754,13 @@ static int lxcfs_open(const char *path, struct fuse_file_info *fi)
 		down_users();
 		return ret;
 	}
+	if (strncmp(path, "/sys", 4) == 0) {
+		up_users();
+		ret = do_sys_open(path, fi);
+		down_users();
+		return ret;
+	}
+
 
 	return -EACCES;
 }
@@ -629,6 +781,13 @@ static int lxcfs_read(const char *path, char *buf, size_t size, off_t offset,
 		down_users();
 		return ret;
 	}
+	if (strncmp(path, "/sys", 4) == 0) {
+		up_users();
+		ret = do_sys_read(path, buf, size, offset, fi);
+		down_users();
+		return ret;
+	}
+
 
 	return -EINVAL;
 }
@@ -667,6 +826,13 @@ static int lxcfs_release(const char *path, struct fuse_file_info *fi)
 		down_users();
 		return ret;
 	}
+	if (strncmp(path, "/sys", 4) == 0) {
+		up_users();
+		ret = do_sys_release(path, fi);
+		down_users();
+		return ret;
+	}
+
 
 	return -EINVAL;
 }
@@ -702,6 +868,8 @@ int lxcfs_chown(const char *path, uid_t uid, gid_t gid)
 	if (strncmp(path, "/proc", 5) == 0)
 		return -EPERM;
 
+	if (strncmp(path, "/sys", 4) == 0) 
+		return -EPERM;
 	return -ENOENT;
 }
 
@@ -742,6 +910,9 @@ int lxcfs_chmod(const char *path, mode_t mode)
 	if (strncmp(path, "/proc", 5) == 0)
 		return -EPERM;
 
+	if (strncmp(path, "/sys", 4) == 0)
+		return -EPERM;
+
 	return -ENOENT;
 }
 

From 3304c65245cde645d9e7637029f74911dcdc84d3 Mon Sep 17 00:00:00 2001
From: wavezhang <baoyafei at gmail.com>
Date: Fri, 22 Mar 2019 15:30:20 +0800
Subject: [PATCH 2/2] Update README.md

---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index 7ff2ec9..d4ece85 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ such as:
 /proc/stat
 /proc/swaps
 /proc/uptime
+/sys/devices/system/cpu/online
 ```
 
 are container aware such that the values displayed (e.g. in `/proc/uptime`)


More information about the lxc-devel mailing list