The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxcfs/pull/237

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
This patch provides an interface for loadavg and consists of the load daemon, the hash table, and an interface of reading loadavg. Container can get its real loadavg by using it.

Hash table stores average load information for all containers.

The load daemon finds the container’s process pid through cgroup file, then gets all threads’ status by reading proc system. Finally it calculates the average load per container and refreshes them just as the Linux kernel did. See:
https://github.com/torvalds/linux/blob/master/kernel/sched/loadavg.c
(calculate the average load function)

Applications in the container can get the container’s real loadavg by using the interface. It should be noted that container must read the interface once when it is created in order to create and store the hash node of this container.

This function is not turned on by default. You can use it by using parameter __-l__. See:
./lxcfs -s -d -l -o allow_other /var/lib/lxcfs

Signed-off-by: zhang2639 [email protected]
Signed-off-by: yuwang [email protected]
From ba5ab95335f6d0c7df843b57dbc88089765bed97 Mon Sep 17 00:00:00 2001
From: zhang2639 <[email protected]>
Date: Wed, 18 Apr 2018 19:22:40 +0800
Subject: [PATCH 1/4] Necessary Instructions For Loadavg

Signed-off-by: zhang2639 <[email protected]>
Signed-off-by: yuwang <[email protected]>
---
 bindings.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/bindings.c b/bindings.c
index 9657160..7e82fb9 100644
--- a/bindings.c
+++ b/bindings.c
@@ -66,6 +66,7 @@ enum {
        LXC_TYPE_PROC_STAT,
        LXC_TYPE_PROC_DISKSTATS,
        LXC_TYPE_PROC_SWAPS,
+       LXC_TYPE_PROC_LOADAVG,
 };
 
 struct file_info {
@@ -4128,7 +4129,8 @@ int proc_getattr(const char *path, struct stat *sb)
                        strcmp(path, "/proc/uptime") == 0 ||
                        strcmp(path, "/proc/stat") == 0 ||
                        strcmp(path, "/proc/diskstats") == 0 ||
-                       strcmp(path, "/proc/swaps") == 0) {
+                       strcmp(path, "/proc/swaps") == 0 ||
+                       strcmp(path, "/proc/loadavg") == 0) {
                sb->st_size = 0;
                sb->st_mode = S_IFREG | 00444;
                sb->st_nlink = 1;
@@ -4148,7 +4150,8 @@ int proc_readdir(const char *path, void *buf, 
fuse_fill_dir_t filler, off_t offs
            filler(buf, "stat", NULL, 0) != 0 ||
            filler(buf, "uptime", NULL, 0) != 0 ||
            filler(buf, "diskstats", NULL, 0) != 0 ||
-           filler(buf, "swaps", NULL, 0) != 0)
+           filler(buf, "swaps", NULL, 0) != 0   ||
+           filler(buf, "loadavg", NULL, 0) != 0)
                return -EINVAL;
        return 0;
 }
@@ -4170,6 +4173,8 @@ int proc_open(const char *path, struct fuse_file_info *fi)
                type = LXC_TYPE_PROC_DISKSTATS;
        else if (strcmp(path, "/proc/swaps") == 0)
                type = LXC_TYPE_PROC_SWAPS;
+       else if (strcmp(path, "/proc/loadavg") == 0)
+               type = LXC_TYPE_PROC_LOADAVG;
        if (type == -1)
                return -ENOENT;
 
@@ -4227,6 +4232,8 @@ int proc_read(const char *path, char *buf, size_t size, 
off_t offset,
                return proc_diskstats_read(buf, size, offset, fi);
        case LXC_TYPE_PROC_SWAPS:
                return proc_swaps_read(buf, size, offset, fi);
+       case LXC_TYPE_PROC_LOADAVG:
+               return proc_loadavg_read(buf, size, offset, fi);
        default:
                return -EINVAL;
        }

From 11c62f5738db64f915e5b85a129e1ca396be24bd Mon Sep 17 00:00:00 2001
From: zhang2639 <[email protected]>
Date: Wed, 2 May 2018 20:02:37 +0800
Subject: [PATCH 2/4] Use hash table to store load information

struct load_head{} contains three locks for thread synchronization
and a pointer to the hash list.
struct load_node{} contains special information of container and
pointers to the hash node.
static struct load_head load_hash[LOAD_SIZE] is hash table.
calc_hash : get the hash of a special container.
init_load : initialize hash table.
insert_node : insert a container node to the hash table.
locate_node : find the specital container node.
del_node : delete a specital container node and return the next node
of it.

Signed-off-by: zhang2639 <[email protected]>
Signed-off-by: yuwang <[email protected]>
---
 bindings.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 151 insertions(+)

diff --git a/bindings.c b/bindings.c
index 7e82fb9..489c355 100644
--- a/bindings.c
+++ b/bindings.c
@@ -80,6 +80,157 @@ struct file_info {
        int cached;
 };
 
+/* The function of hash table.*/
+#define LOAD_SIZE 100 /*the size of hash_table */
+static int calc_hash(char *name)
+{
+       unsigned int hash = 0;
+       unsigned int x = 0;
+       /* ELFHash algorithm. */
+       while (*name) {
+               hash = (hash << 4) + *name++;
+               x = hash & 0xf0000000;
+               if (x != 0)
+                       hash ^= (x >> 24);
+               hash &= ~x;
+       }
+       return ((hash & 0x7fffffff) % LOAD_SIZE);
+}
+
+struct load_node {
+       char *cg;  /*cg */
+       unsigned long avenrun[3];               /* Load averages */
+       unsigned int run_pid;
+       unsigned int total_pid;
+       unsigned int last_pid;
+       int cfd; /* The file descriptor of the mounted cgroup */
+       struct  load_node *next;
+       struct  load_node **pre;
+};
+
+struct load_head {
+       /*
+        * The lock is about insert load_node and refresh load_node.To the first
+        * load_node of each hash bucket, insert andrefresh in this hash bucket 
is
+        * mutually exclusive.
+        */
+       pthread_mutex_t lock;
+       /*
+        * The rdlock is about read loadavg and delete load_node.To each hash
+        * bucket, read and delete is mutually exclusive. But at the same time, 
we
+        * allow paratactic read operation. This rdlock is at list level.
+        */
+       pthread_rwlock_t rdlock;
+       /*
+        * The rilock is about read loadavg and insert load_node.To the first
+        * load_node of each hash bucket, read and insert is mutually exclusive.
+        * But at the same time, we allow paratactic read operation.
+        */
+       pthread_rwlock_t rilock;
+       struct load_node *next;
+};
+
+static struct load_head load_hash[LOAD_SIZE]; /* hash table */
+/*
+ * init_load initialize the hash table.
+ * Return 0 on success, return -1 on failure.
+ */
+static int init_load(void)
+{
+       int i;
+       int ret;
+
+       for (i = 0; i < LOAD_SIZE; i++) {
+               load_hash[i].next = NULL;
+               ret = pthread_mutex_init(&load_hash[i].lock, NULL);
+               if (ret != 0) {
+                       lxcfs_error("%s\n", "Failed to initialize lock");
+                       goto out3;
+               }
+               ret = pthread_rwlock_init(&load_hash[i].rdlock, NULL);
+               if (ret != 0) {
+                       lxcfs_error("%s\n", "Failed to initialize rdlock");
+                       goto out2;
+               }
+               ret = pthread_rwlock_init(&load_hash[i].rilock, NULL);
+               if (ret != 0) {
+                       lxcfs_error("%s\n", "Failed to initialize rilock");
+                       goto out1;
+               }
+       }
+       return 0;
+out1:
+       pthread_rwlock_destroy(&load_hash[i].rdlock);
+out2:
+       pthread_mutex_destroy(&load_hash[i].lock);
+out3:
+       while (i > 0) {
+               i--;
+               pthread_mutex_destroy(&load_hash[i].lock);
+               pthread_rwlock_destroy(&load_hash[i].rdlock);
+               pthread_rwlock_destroy(&load_hash[i].rilock);
+       }
+       return -1;
+}
+
+static void insert_node(struct load_node **n, int locate)
+{
+       struct load_node *f;
+
+       pthread_mutex_lock(&load_hash[locate].lock);
+       pthread_rwlock_wrlock(&load_hash[locate].rilock);
+       f = load_hash[locate].next;
+       load_hash[locate].next = *n;
+
+       (*n)->pre = &(load_hash[locate].next);
+       if (f)
+               f->pre = &((*n)->next);
+       (*n)->next = f;
+       pthread_mutex_unlock(&load_hash[locate].lock);
+       pthread_rwlock_unlock(&load_hash[locate].rilock);
+}
+/*
+ * locate_node() finds special node. Not return NULL means success.
+ * It should be noted that rdlock isn't unlocked at the end of code
+ * because this function is used to read special node. Delete is not
+ * allowed before read has ended.
+ * unlock rdlock only in proc_loadavg_read().
+ */
+static struct load_node *locate_node(char *cg, int locate)
+{
+       struct load_node *f = NULL;
+       int i = 0;
+
+       pthread_rwlock_rdlock(&load_hash[locate].rilock);
+       pthread_rwlock_rdlock(&load_hash[locate].rdlock);
+       if (load_hash[locate].next == NULL) {
+               pthread_rwlock_unlock(&load_hash[locate].rilock);
+               return f;
+       }
+       f = load_hash[locate].next;
+       pthread_rwlock_unlock(&load_hash[locate].rilock);
+       while (f && ((i = strcmp(f->cg, cg)) != 0))
+               f = f->next;
+       return f;
+}
+/* Delete the load_node n and return the next node of it. */
+static struct load_node *del_node(struct load_node *n, int locate)
+{
+       struct load_node *g;
+
+       pthread_rwlock_wrlock(&load_hash[locate].rdlock);
+       if (n->next == NULL) {
+               *(n->pre) = NULL;
+       } else {
+               *(n->pre) = n->next;
+               n->next->pre = n->pre;
+       }
+       g = n->next;
+       free(n->cg);
+       free(n);
+       pthread_rwlock_unlock(&load_hash[locate].rdlock);
+       return g;
+}
 /* Reserve buffer size to account for file size changes. */
 #define BUF_RESERVE_SIZE 512
 

From af54f8651bcab312c2a119d47ae43da3793b59ce Mon Sep 17 00:00:00 2001
From: zhang2639 <[email protected]>
Date: Wed, 2 May 2018 20:11:29 +0800
Subject: [PATCH 3/4] Calculate the average load and read them.

Use load daemon to calculate the average load and use proc_loadavg_read() to
read loadavg
calc_pid : find the process pid from cgroup path of a container.
calc_load : calculate the loadavg of a container.
refresh_load : refresh the loadavg of a container.
load_begin : traverse the hash table and update it.

Signed-off-by: zhang2639 <[email protected]>
Signed-off-by: yuwang <[email protected]>
---
 bindings.c | 373 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 bindings.h |   1 +
 lxcfs.c    |  24 +++-
 3 files changed, 397 insertions(+), 1 deletion(-)

diff --git a/bindings.c b/bindings.c
index 489c355..edab10e 100644
--- a/bindings.c
+++ b/bindings.c
@@ -82,6 +82,22 @@ struct file_info {
 
 /* The function of hash table.*/
 #define LOAD_SIZE 100 /*the size of hash_table */
+#define FLUSH_TIME 5  /*the flush rate */
+#define DEPTH_DIR 3   /*the depth of per cgroup */
+/* The function of calculate loadavg .*/
+#define FSHIFT         11              /* nr of bits of precision */
+#define FIXED_1                (1<<FSHIFT)     /* 1.0 as fixed-point */
+#define EXP_1          1884            /* 1/exp(5sec/1min) as fixed-point */
+#define EXP_5          2014            /* 1/exp(5sec/5min) */
+#define EXP_15         2037            /* 1/exp(5sec/15min) */
+#define LOAD_INT(x) ((x) >> FSHIFT)
+#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100)
+/* 
+ * This parameter is used for proc_loadavg_read().
+ * 1 means use loadavg, 0 means not use.
+ */
+static int loadavg = 0;
+
 static int calc_hash(char *name)
 {
        unsigned int hash = 0;
@@ -4244,6 +4260,363 @@ static int proc_swaps_read(char *buf, size_t size, 
off_t offset,
        return rv;
 }
 
+/*
+ * Find the process pid from cgroup path.
+ * eg:from /sys/fs/cgroup/cpu/docker/containerid/cgroup.procs to find the 
process pid.
+ * @pid_buf : put pid to pid_buf.
+ * @dpath : the path of cgroup. eg: /docker/containerid or 
/docker/containerid/child-cgroup ...
+ * @depth : the depth of cgroup in container.
+ * @sum : return the number of pid.
+ * @cfd : the file descriptor of the mounted cgroup. eg: /sys/fs/cgroup/cpu
+ */
+static int calc_pid(char ***pid_buf, char *dpath, int depth, int sum, int cfd)
+{
+       DIR *dir;
+       int fd;
+       struct dirent *file;
+       FILE *f = NULL;
+       size_t linelen = 0;
+       char *line = NULL;
+       int pd;
+       char *path_dir, *path;
+       char **pid;
+
+       /* path = dpath + "/cgroup.procs" + /0 */
+       path = (char *)malloc(strlen(dpath) + 20);
+       if (!path) {
+               lxcfs_error("Failed to malloc %s in calc_pid!\n", dpath);
+               return sum;
+       }
+
+       strcpy(path, dpath);
+       fd = openat(cfd, path, O_RDONLY);
+       if (fd < 0)
+               goto out;
+
+       dir = fdopendir(fd);
+       if (dir == NULL)
+               goto out;
+
+       while (((file = readdir(dir)) != NULL) && depth > 0) {
+               if (strncmp(file->d_name, ".", 1) == 0)
+                       continue;
+               if (file->d_type == DT_DIR) {
+                       /* path + '/' + d_name +/0 */
+                       path_dir = (char *)malloc(strlen(path) + 2 + 
sizeof(file->d_name));
+                       if (!path_dir) {
+                               lxcfs_error("Failed to malloc %s in 
calc_pid!\n", path);
+                               continue;
+                       }
+                       strcpy(path_dir, path);
+                       strcat(path_dir, "/");
+                       strcat(path_dir, file->d_name);
+                       pd = depth - 1;
+                       sum = calc_pid(pid_buf, path_dir, pd, sum, cfd);
+                       free(path_dir);
+               }
+       }
+       closedir(dir);
+
+       /* realloc() failed */
+       if (sum == -1)
+               goto out;
+
+       strcat(path, "/cgroup.procs");
+       fd = openat(cfd, path, O_RDONLY);
+       if (fd < 0)
+               goto out;
+
+       f = fdopen(fd, "r");
+       if (!f)
+               goto out;
+
+       while (getline(&line, &linelen, f) != -1) {
+               pid = (char **)realloc(*pid_buf, sizeof(char *) * (sum + 1));
+               if (pid == NULL) {
+                       lxcfs_error("%s\n", "realloc error!");
+                       for (; sum > 0; sum--)
+                               free((*pid_buf)[sum - 1]);
+                       sum = -1;
+                       goto out;
+               }
+               *pid_buf = pid;
+               do {
+                       *(*pid_buf + sum) = (char *)malloc(strlen(line) + 3);
+               } while (*(*pid_buf + sum) == NULL);
+               strcpy(*(*pid_buf + sum), line);
+               sum++;
+       }
+       fclose(f);
+out:
+       free(path);
+       return sum;
+}
+/*
+ * calc_load calculates the load according to the following formula:
+ * load1 = load0 * exp + active * (1 - exp)
+ *
+ * load1: the new loadavg.
+ * load0: the former loadavg.
+ * active: the total number of running pid at this moment.
+ * exp: the fixed-point defined in the beginning.
+ */
+static unsigned long
+calc_load(unsigned long load, unsigned long exp, unsigned long active)
+{
+       unsigned long newload;
+
+       active = active > 0 ? active * FIXED_1 : 0;
+       newload = load * exp + active * (FIXED_1 - exp);
+       if (active >= load)
+               newload += FIXED_1 - 1;
+
+       return newload / FIXED_1;
+}
+
+/*
+ * Return 0 means that container p->cg is closed.
+ * Return -1 means that error occurred in refresh.
+ * Positive num equals the total number of pid.
+ */
+static int refresh_load(struct load_node *p, char *path)
+{
+       FILE *f = NULL;
+       char **idbuf;
+       char proc_path[256];
+       int i, ret, run_pid = 0, total_pid = 0, last_pid = 0;
+       char *line = NULL;
+       size_t linelen = 0;
+       int sum, length;
+       DIR *dp;
+       struct dirent *file;
+
+       idbuf = (char **)malloc(sizeof(char *));
+       if (!idbuf) {
+               lxcfs_error("Refresh container:%s failed for malloc!\n", p->cg);
+               return -1;
+       }
+       sum = calc_pid(&idbuf, path, DEPTH_DIR, 0, p->cfd);
+       /*  normal exit and abnormal exit */
+       if (sum == 0 || sum == -1)
+               goto out;
+
+       for (i = 0; i < sum; i++) {
+               /*clean up '\n' */
+               length = strlen(idbuf[i])-1;
+               idbuf[i][length] = '\0';
+               do {
+                       ret = snprintf(proc_path, 256, "/proc/%s/task", 
idbuf[i]);
+               } while (ret < 0);
+
+               dp = opendir(proc_path);
+               if (!dp) {
+                       lxcfs_error("%s\n", "Open proc_path failed in 
refresh_load.");
+                       continue;
+               }
+               while ((file = readdir(dp)) != NULL) {
+                       if (strncmp(file->d_name, ".", 1) == 0)
+                               continue;
+                       total_pid++;
+                       /* We make the biggest pid become last_pid.*/
+                       ret = atof(file->d_name);
+                       last_pid = (ret > last_pid) ? ret : last_pid;
+
+                       do {
+                               ret = snprintf(proc_path, 256, 
"/proc/%s/task/%s/status", idbuf[i], file->d_name);
+                       } while (ret < 0);
+                       f = fopen(proc_path, "r");
+                       if (f != NULL) {
+                               while (getline(&line, &linelen, f) != -1) {
+                                       /* Find State */
+                                       if ((line[0] == 'S') && (line[1] == 
't'))
+                                               break;
+                               }
+                       if ((line[7] == 'R') || (line[7] == 'D'))
+                               run_pid++;
+                       fclose(f);
+                       }
+               }
+               closedir(dp);
+       }
+       /*Calculate the loadavg.*/
+       p->avenrun[0] = calc_load(p->avenrun[0], EXP_1, run_pid);
+       p->avenrun[1] = calc_load(p->avenrun[1], EXP_5, run_pid);
+       p->avenrun[2] = calc_load(p->avenrun[2], EXP_15, run_pid);
+       p->run_pid = run_pid;
+       p->total_pid = total_pid;
+       p->last_pid = last_pid;
+
+       free(line);
+       for (; i > 0; i--)
+               free(idbuf[i-1]);
+out:
+       free(idbuf);
+       return sum;
+}
+/*
+ * Traverse the hash table and update it.
+ */
+void *load_begin(void *arg)
+{
+
+       char *path = NULL;
+       int i, sum, length, ret;
+       struct load_node *f;
+       int first_node;
+       clock_t time1, time2;
+
+       while (1) {
+               time1 = clock();
+               for (i = 0; i < LOAD_SIZE; i++) {
+                       pthread_mutex_lock(&load_hash[i].lock);
+                       if (load_hash[i].next == NULL) {
+                               pthread_mutex_unlock(&load_hash[i].lock);
+                               continue;
+                       }
+                       f = load_hash[i].next;
+                       first_node = 1;
+                       while (f) {
+                               length = strlen(f->cg) + 2;
+                               do {
+                                       /* strlen(f->cg) + '.' or '' + \0 */
+                                       path = (char *)malloc(length);
+                               } while (!path);
+
+                               ret = snprintf(path, length, "%s%s", *(f->cg) 
== '/' ? "." : "", f->cg);
+                               if (ret < 0 || ret > length - 1) {
+                                       /* snprintf failed, ignore the node.*/
+                                       lxcfs_error("Refresh node %s failed for 
snprintf().\n", f->cg);
+                                       goto out;
+                               }
+                               sum = refresh_load(f, path);
+                               if (sum == 0) {
+                                       f = del_node(f, i);
+                               } else {
+out:                           f = f->next;
+                               }
+                               free(path);
+                               /* load_hash[i].lock locks only on the first 
node.*/
+                               if (first_node == 1) {
+                                       first_node = 0;
+                                       
pthread_mutex_unlock(&load_hash[i].lock);
+                               }
+                       }
+               }
+               time2 = clock();
+               usleep(FLUSH_TIME * 1000000 - (int)((time2 - time1) * 1000000 / 
CLOCKS_PER_SEC));
+       }
+}
+
+static int proc_loadavg_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;
+       pid_t initpid;
+       char *cg;
+       size_t total_len = 0;
+       char *cache = d->buf;
+       struct load_node *n;
+       int hash;
+       int cfd;
+       unsigned long a, b, c;
+
+       if (offset) {
+               if (offset > d->size)
+                       return -EINVAL;
+               if (!d->cached)
+                       return 0;
+               int left = d->size - offset;
+               total_len = left > size ? size : left;
+               memcpy(buf, cache + offset, total_len);
+               return total_len;
+       }
+       if (!loadavg)
+               return read_file("/proc/loadavg", buf, size, d);
+
+       initpid = lookup_initpid_in_store(fc->pid);
+       if (initpid <= 0)
+               initpid = fc->pid;
+       cg = get_pid_cgroup(initpid, "cpu");
+       if (!cg)
+               return read_file("/proc/loadavg", buf, size, d);
+
+       prune_init_slice(cg);
+       hash = calc_hash(cg);
+       n = locate_node(cg, hash);
+
+       /* First time */
+       if (n == NULL) {
+               if (!find_mounted_controller("cpu", &cfd)) {
+                       /*
+                        * In locate_node() above, pthread_rwlock_unlock() 
isn't used
+                        * because delete is not allowed before read has ended.
+                        */
+                       pthread_rwlock_unlock(&load_hash[hash].rdlock);
+                       return 0;
+               }
+               n = (struct load_node *)malloc(sizeof(struct load_node));
+               if (!n) {
+                       lxcfs_error("Create node %s failed for malloc().\n", 
cg);
+                       pthread_rwlock_unlock(&load_hash[hash].rdlock);
+                       return read_file("/proc/loadavg", buf, size, d);
+               }
+               do {
+                       n->cg = (char *)malloc(strlen(cg)+1);
+               } while (!n->cg);
+               strcpy(n->cg, cg);
+               n->avenrun[0] = 0;
+               n->avenrun[1] = 0;
+               n->avenrun[2] = 0;
+               n->run_pid = 0;
+               n->total_pid = 1;
+               n->last_pid = initpid;
+               n->cfd = cfd;
+               insert_node(&n, hash);
+       }
+       a = n->avenrun[0] + (FIXED_1/200);
+       b = n->avenrun[1] + (FIXED_1/200);
+       c = n->avenrun[2] + (FIXED_1/200);
+       total_len = snprintf(d->buf, d->buflen, "%lu.%02lu %lu.%02lu %lu.%02lu 
%d/%d %d\n",
+               LOAD_INT(a), LOAD_FRAC(a),
+               LOAD_INT(b), LOAD_FRAC(b),
+               LOAD_INT(c), LOAD_FRAC(c),
+               n->run_pid, n->total_pid, n->last_pid);
+       pthread_rwlock_unlock(&load_hash[hash].rdlock);
+       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;
+}
+/* Return a positive number on success, return 0 on failure.*/
+pthread_t load_daemon(int load_use)
+{
+       int ret;
+       pthread_t pid;
+
+       ret = init_load();
+       if (ret == -1) {
+               lxcfs_error("%s\n", "Initialize hash_table fails in 
load_daemon!");
+               return 0;
+       }
+       ret = pthread_create(&pid, NULL, load_begin, NULL);
+       if (ret != 0) {
+               lxcfs_error("%s\n", "Create pthread fails in load_daemon!");
+               load_free();
+               return 0;
+       }
+       /* use loadavg, here loadavg = 1*/
+       loadavg = load_use;
+       return pid;
+}
+
 static off_t get_procfile_size(const char *which)
 {
        FILE *f = fopen(which, "r");
diff --git a/bindings.h b/bindings.h
index c663287..a34ac5f 100644
--- a/bindings.h
+++ b/bindings.h
@@ -32,5 +32,6 @@ 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 pthread_t load_daemon(int load_use);
 
 #endif /* __LXCFS_BINDINGS_H */
diff --git a/lxcfs.c b/lxcfs.c
index 62cfd35..848f9b4 100644
--- a/lxcfs.c
+++ b/lxcfs.c
@@ -745,8 +745,9 @@ static void usage()
 {
        fprintf(stderr, "Usage:\n");
        fprintf(stderr, "\n");
-       fprintf(stderr, "lxcfs [-f|-d] [-p pidfile] mountpoint\n");
+       fprintf(stderr, "lxcfs [-f|-d] -l [-p pidfile] mountpoint\n");
        fprintf(stderr, "  -f running foreground by default; -d enable debug 
output \n");
+       fprintf(stderr, "  -l use loadavg \n");
        fprintf(stderr, "  Default pidfile is %s/lxcfs.pid\n", RUNTIME_PATH);
        fprintf(stderr, "lxcfs -h\n");
        exit(1);
@@ -848,6 +849,10 @@ int main(int argc, char *argv[])
        char *pidfile = NULL, *v = NULL;
        size_t pidfile_len;
        bool debug = false;
+       pthread_t pid;
+       int s = 0;
+       char *error;
+       bool load_use = false;
        /*
         * what we pass to fuse_main is:
         * argv[0] -s [-f|-d] -o allow_other,directio argv[1] NULL
@@ -859,6 +864,9 @@ int main(int argc, char *argv[])
        swallow_arg(&argc, argv, "-s");
        swallow_arg(&argc, argv, "-f");
        debug = swallow_arg(&argc, argv, "-d");
+       if (swallow_arg(&argc, argv, "-l")) {
+               load_use = true;
+       }
        if (swallow_option(&argc, argv, "-o", &v)) {
                if (strcmp(v, "allow_other") != 0) {
                        fprintf(stderr, "Warning: unexpected fuse option %s\n", 
v);
@@ -902,6 +910,20 @@ int main(int argc, char *argv[])
        if ((pidfd = set_pidfile(pidfile)) < 0)
                goto out;
 
+       if (load_use == true) {
+               dlerror();    /* Clear any existing error */
+               pthread_t (*load_daemon)(int);
+
+               load_daemon = (pthread_t (*)(int)) dlsym(dlopen_handle, 
"load_daemon");
+               error = dlerror();
+               if (error != NULL) {
+                       lxcfs_error("load_daemon fails:%s\n", error);
+                       goto out;
+               }
+               pid = load_daemon(1);
+               if (pid == 0)
+                       goto out;
+       }
        if (!fuse_main(nargs, newargv, &lxcfs_ops, NULL))
                ret = EXIT_SUCCESS;
 

From dfdead46f72e5eef22bccc61bac62af434b992a4 Mon Sep 17 00:00:00 2001
From: zhang2639 <[email protected]>
Date: Wed, 2 May 2018 20:17:15 +0800
Subject: [PATCH 4/4] Claim and use load_free() to free hash table.

Signed-off-by: zhang2639 <[email protected]>
Signed-off-by: yuwang <[email protected]>
---
 bindings.c | 33 +++++++++++++++++++++++++++++++++
 bindings.h |  1 +
 lxcfs.c    | 23 +++++++++++++++++++++++
 3 files changed, 57 insertions(+)

diff --git a/bindings.c b/bindings.c
index edab10e..5c172fc 100644
--- a/bindings.c
+++ b/bindings.c
@@ -247,6 +247,39 @@ static struct load_node *del_node(struct load_node *n, int 
locate)
        pthread_rwlock_unlock(&load_hash[locate].rdlock);
        return g;
 }
+
+void load_free(void)
+{
+       int i;
+       struct load_node *f, *p;
+
+       for (i = 0; i < LOAD_SIZE; i++) {
+               pthread_mutex_lock(&load_hash[i].lock);
+               pthread_rwlock_wrlock(&load_hash[i].rilock);
+               pthread_rwlock_wrlock(&load_hash[i].rdlock);
+               if (load_hash[i].next == NULL) {
+                       pthread_mutex_unlock(&load_hash[i].lock);
+                       pthread_mutex_destroy(&load_hash[i].lock);
+                       pthread_rwlock_unlock(&load_hash[i].rilock);
+                       pthread_rwlock_destroy(&load_hash[i].rilock);
+                       pthread_rwlock_unlock(&load_hash[i].rdlock);
+                       pthread_rwlock_destroy(&load_hash[i].rdlock);
+                       continue;
+               }
+               for (f = load_hash[i].next; f; ) {
+                       free(f->cg);
+                       p = f->next;
+                       free(f);
+                       f = p;
+               }
+               pthread_mutex_unlock(&load_hash[i].lock);
+               pthread_mutex_destroy(&load_hash[i].lock);
+               pthread_rwlock_unlock(&load_hash[i].rilock);
+               pthread_rwlock_destroy(&load_hash[i].rilock);
+               pthread_rwlock_unlock(&load_hash[i].rdlock);
+               pthread_rwlock_destroy(&load_hash[i].rdlock);
+       }
+}
 /* Reserve buffer size to account for file size changes. */
 #define BUF_RESERVE_SIZE 512
 
diff --git a/bindings.h b/bindings.h
index a34ac5f..6563011 100644
--- a/bindings.h
+++ b/bindings.h
@@ -33,5 +33,6 @@ 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 pthread_t load_daemon(int load_use);
+extern void load_free(void);
 
 #endif /* __LXCFS_BINDINGS_H */
diff --git a/lxcfs.c b/lxcfs.c
index 848f9b4..c3535c9 100644
--- a/lxcfs.c
+++ b/lxcfs.c
@@ -926,6 +926,29 @@ int main(int argc, char *argv[])
        }
        if (!fuse_main(nargs, newargv, &lxcfs_ops, NULL))
                ret = EXIT_SUCCESS;
+       
+       if (load_use == true) {
+               s = pthread_cancel(pid);
+               if (s == 0) {
+                       s = pthread_join(pid, NULL); /* Make sure sub thread 
has been canceled. */
+                       if (s != 0) {
+                               lxcfs_error("%s\n", "load_free error!");
+                               goto out;
+                       }
+                       dlerror();    /* Clear any existing error */
+                       void (*load_free)(void);
+
+                       load_free = (void (*)(void)) dlsym(dlopen_handle, 
"load_free");
+                       error = dlerror();
+                       if (error != NULL) {
+                               lxcfs_error("load_free error: %s\n", error);
+                               goto out;
+                       }
+                       load_free();
+               } else {
+                       lxcfs_error("%s\n", "load_free error!");
+               }
+       }
 
 out:
        if (dlopen_handle)
_______________________________________________
lxc-devel mailing list
[email protected]
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to