]> git.proxmox.com Git - mirror_lxcfs.git/commitdiff
add cache for proc file, for support multiple read
authorYe Yin <eyniy@qq.com>
Thu, 9 Apr 2015 11:01:10 +0000 (19:01 +0800)
committerYe Yin <eyniy@qq.com>
Thu, 9 Apr 2015 11:03:19 +0000 (19:03 +0800)
Signed-off-by: Ye Yin <eyniy@qq.com>
Makefile.am
lxcfs.c
tests/test-read.c [new file with mode: 0644]
tests/test_read_proc.sh [new file with mode: 0755]

index b083b0a072fb0580a584ac6fbb1c8063665ed5a2..7b690e28f46c39428e38d8dc591eb56b435eef2b 100644 (file)
@@ -25,6 +25,11 @@ lxcfs.1: lxcfs lxcfs.man.add
        $(HELP2MAN) -n "Set up cgroup fs for containers" --no-discard-stderr -s 1 -I lxcfs.man.add -N ./lxcfs > lxcfs.1
 endif
 
+TEST_READ: tests/test-read.c
+       $(CC) -o tests/test-read tests/test-read.c
+
+tests: TEST_READ
+
 distclean:
        rm -rf .deps/ \
                INSTALL \
diff --git a/lxcfs.c b/lxcfs.c
index 84c10458e6c8eb3b44972bc0a9f1700323cf52d0..2ec471d4d2555197683dde0a70275f97cd9af881 100644 (file)
--- a/lxcfs.c
+++ b/lxcfs.c
@@ -60,8 +60,12 @@ struct file_info {
        int type;
        char *buf;  // unused as of yet
        int buflen;
+       int size; //actual data size
 };
 
+/* reserve buffer size, for cpuall in /proc/stat */
+#define BUF_RESERVE_SIZE 256
+
 static char *must_copy_string(void *parent, const char *str)
 {
        if (!str)
@@ -662,6 +666,10 @@ static void do_release_file_info(struct file_info *f)
         * all file_info fields which are nih_alloc()d with f as parent
         * will be automatically freed
         */
+       if (!f->buf) {
+               nih_free(f->buf);
+               f->buf = NULL;
+       }
        nih_free(f);
 }
 
@@ -1591,15 +1599,24 @@ static int proc_meminfo_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;
        nih_local char *cg = get_pid_cgroup(fc->pid, "memory");
        nih_local char *memlimit_str = NULL, *memusage_str = NULL, *memstat_str = NULL;
        unsigned long memlimit = 0, memusage = 0, cached = 0, hosttotal = 0;
        char *line = NULL;
        size_t linelen = 0, total_len = 0;
+       char *cache = d->buf;
+       size_t cache_size = d->buflen;
        FILE *f;
 
-       if (offset)
-               return -EINVAL;
+       if (offset){
+               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;
+       }
 
        if (!cg)
                return 0;
@@ -1648,12 +1665,17 @@ static int proc_meminfo_read(char *buf, size_t size, off_t offset,
                        printme = lbuf;
                } else
                        printme = line;
-               l = snprintf(buf, size, "%s", printme);
-               buf += l;
-               size -= l;
-               total_len += l;
+
+               l = snprintf(cache, cache_size, "%s", printme);
+               cache += l;
+               cache_size -= l;
+               total_len += l; 
        }
 
+       d->size = total_len;
+       if (total_len > size ) total_len = size;
+       memcpy(buf, d->buf, total_len);
+
        fclose(f);
        free(line);
        return total_len;
@@ -1739,16 +1761,25 @@ static int proc_cpuinfo_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;
        nih_local char *cg = get_pid_cgroup(fc->pid, "cpuset");
        nih_local char *cpuset = NULL;
        char *line = NULL;
        size_t linelen = 0, total_len = 0;
        bool am_printing = false;
        int curcpu = -1;
+       char *cache = d->buf;
+       size_t cache_size = d->buflen;
        FILE *f;
 
-       if (offset)
-               return -EINVAL;
+       if (offset){
+               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;       
+       }
 
        if (!cg)
                return 0;
@@ -1767,21 +1798,41 @@ static int proc_cpuinfo_read(char *buf, size_t size, off_t offset,
                        am_printing = cpuline_in_cpuset(line, cpuset);
                        if (am_printing) {
                                curcpu ++;
-                               l = snprintf(buf, size, "processor      : %d\n", curcpu);
-                               buf += l;
-                               size -= l;
-                               total_len += l;
+                               l = snprintf(cache, cache_size, "processor      : %d\n", curcpu);
+                               if (l < cache_size){
+                                       cache += l;
+                                       cache_size -= l;
+                                       total_len += l;
+                               }else{
+                                       cache += cache_size;
+                                       total_len += cache_size;
+                                       cache_size = 0;
+                                       break;
+                               }
                        }
                        continue;
                }
                if (am_printing) {
-                       l = snprintf(buf, size, "%s", line);
-                       buf += l;
-                       size -= l;
-                       total_len += l;
+                       l = snprintf(cache, cache_size, "%s", line);
+                       if (l < cache_size) {
+                               cache += l;
+                               cache_size -= l;
+                               total_len += l;
+                       } else {
+                               cache += cache_size;
+                               total_len += cache_size;
+                               cache_size = 0;
+                               break;
+                       }
                }
        }
 
+       d->size = total_len;
+       if (total_len > size ) total_len = size;
+
+       /* read from off 0 */
+       memcpy(buf, d->buf, total_len);
+
        fclose(f);
        free(line);
        return total_len;
@@ -1791,15 +1842,30 @@ static int proc_stat_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;
        nih_local char *cg = get_pid_cgroup(fc->pid, "cpuset");
        nih_local char *cpuset = NULL;
        char *line = NULL;
        size_t linelen = 0, total_len = 0;
        int curcpu = -1; /* cpu numbering starts at 0 */
+       unsigned long user = 0, nice = 0, system = 0, idle = 0, iowait = 0, irq = 0, softirq = 0, steal = 0, guest = 0;
+       unsigned long user_sum = 0, nice_sum = 0, system_sum = 0, idle_sum = 0, iowait_sum = 0,
+                                       irq_sum = 0, softirq_sum = 0, steal_sum = 0, guest_sum = 0;
+#define CPUALL_MAX_SIZE BUF_RESERVE_SIZE
+       char cpuall[CPUALL_MAX_SIZE];
+       /* reserve for cpu all */
+       char *cache = d->buf + CPUALL_MAX_SIZE;
+       size_t cache_size = d->buflen - CPUALL_MAX_SIZE;
        FILE *f;
 
-       if (offset)
-               return -EINVAL;
+       if (offset){
+               if (offset > d->size)
+                       return -EINVAL;
+               int left = d->size - offset;
+               total_len = left > size ? size: left;
+               memcpy(buf, d->buf + offset, total_len);
+               return total_len;       
+       }
 
        if (!cg)
                return 0;
@@ -1812,6 +1878,12 @@ static int proc_stat_read(char *buf, size_t size, off_t offset,
        if (!f)
                return 0;
 
+       //skip first line
+       if (getline(&line, &linelen, f) < 0) {
+               fprintf(stderr, "proc_stat_read read first line failed\n");
+               goto out;
+       }
+
        while (getline(&line, &linelen, f) != -1) {
                size_t l;
                int cpu;
@@ -1820,11 +1892,19 @@ static int proc_stat_read(char *buf, size_t size, off_t offset,
 
                if (sscanf(line, "cpu%9[^ ]", cpu_char) != 1) {
                        /* not a ^cpuN line containing a number N, just print it */
-                       l = snprintf(buf, size, "%s", line);
-                       buf += l;
-                       size -= l;
-                       total_len += l;
-                       continue;
+                       l = snprintf(cache, cache_size, "%s", line);
+                       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;
+                       }
                }
 
                if (sscanf(cpu_char, "%d", &cpu) != 1)
@@ -1836,12 +1916,46 @@ static int proc_stat_read(char *buf, size_t size, off_t offset,
                c = strchr(line, ' ');
                if (!c)
                        continue;
-               l = snprintf(buf, size, "cpu%d %s", curcpu, c);
-               buf += l;
-               size -= l;
+               l = snprintf(cache, cache_size, "cpu%d %s", curcpu, c);
+               cache += l;
+               cache_size -= l;
                total_len += l;
-       }
-
+               
+               if (sscanf(line, "%*s %lu %lu %lu %lu %lu %lu %lu %lu %lu", &user, &nice, &system, &idle, &iowait, &irq,
+                       &softirq, &steal, &guest) != 9)
+                       continue;
+               user_sum += user;
+               nice_sum += nice;
+               system_sum += system;
+               idle_sum += idle;
+               iowait_sum += iowait;
+               irq_sum += irq;
+               softirq_sum += softirq;
+               steal_sum += steal;
+               guest_sum += guest;     
+       }
+
+       cache = d->buf;
+
+       int cpuall_len = snprintf(cpuall, CPUALL_MAX_SIZE, "%s %lu %lu %lu %lu %lu %lu %lu %lu %lu\n", 
+               "cpu ", user_sum, nice_sum, system_sum, idle_sum, iowait_sum, irq_sum, softirq_sum, steal_sum, guest_sum);
+       if (cpuall_len > 0 && cpuall_len < CPUALL_MAX_SIZE){
+               memcpy(cache, cpuall, cpuall_len);
+               cache += cpuall_len;    
+       }else{
+               /* shouldn't happen */
+               fprintf(stderr, "proc_stat_read copy cpuall failed, cpuall_len=%d\n", cpuall_len);
+               cpuall_len = 0;
+       }
+
+       memmove(cache, d->buf + CPUALL_MAX_SIZE, total_len);
+       total_len += cpuall_len;
+       d->size = total_len;
+       if (total_len > size ) total_len = size;
+
+       memcpy(buf, d->buf, total_len);
+       fprintf(stderr, "total_len = %d, buflen = %d\n", d->size, d->buflen);
+out:
        fclose(f);
        free(line);
        return total_len;
@@ -2017,12 +2131,20 @@ static int proc_uptime_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;
        long int reaperage = getreaperage(fc->pid);;
        long int idletime = getprocidle();
+       size_t total_len = 0;
 
-       if (offset)
-               return -EINVAL;
-       return snprintf(buf, size, "%ld %ld\n", reaperage, idletime);
+       if (offset){
+               if (offset > d->size)
+                       return -EINVAL;
+               return 0;
+       }
+
+       total_len = snprintf(buf, size, "%ld %ld\n", reaperage, idletime);
+       d->size = total_len;
+       return total_len;
 }
 
 static int proc_diskstats_read(char *buf, size_t size, off_t offset,
@@ -2030,6 +2152,7 @@ static int proc_diskstats_read(char *buf, size_t size, off_t offset,
 {
        char dev_name[72];
        struct fuse_context *fc = fuse_get_context();
+       struct file_info *d = (struct file_info *)fi->fh;
        nih_local char *cg = get_pid_cgroup(fc->pid, "blkio");
        nih_local char *io_serviced_str = NULL, *io_merged_str = NULL, *io_service_bytes_str = NULL,
                        *io_wait_time_str = NULL, *io_service_time_str = NULL;
@@ -2045,8 +2168,11 @@ static int proc_diskstats_read(char *buf, size_t size, off_t offset,
        int i = 0;
        FILE *f;
 
-       if (offset)
-               return -EINVAL;
+       if (offset){
+               if (offset > d->size)
+                       return -EINVAL;
+               return 0;
+       }
 
        if (!cg)
                return 0;
@@ -2115,6 +2241,8 @@ static int proc_diskstats_read(char *buf, size_t size, off_t offset,
                total_len += l;
        }
 
+       d->size = total_len;
+
        fclose(f);
        free(line);
        return total_len;
@@ -2199,6 +2327,12 @@ static int proc_open(const char *path, struct fuse_file_info *fi)
        memset(info, 0, sizeof(*info));
        info->type = type;
 
+       info->buflen = get_procfile_size(path) + BUF_RESERVE_SIZE;
+       info->buf = NIH_MUST( nih_alloc(NULL, info->buflen) );
+       memset(info->buf, 0, info->buflen);
+       /* set actual size to buffer size */
+       info->size = info->buflen; 
+
        fi->fh = (unsigned long)info;
        return 0;
 }
diff --git a/tests/test-read.c b/tests/test-read.c
new file mode 100644 (file)
index 0000000..4c96a57
--- /dev/null
@@ -0,0 +1,47 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define BUFSIZE 1025
+char buf[BUFSIZE];
+
+int read_count = 2;
+
+int main(int argc, char *argv[]){
+       if(argc < 3){
+               fprintf(stderr, "usage: %s <file> <count> [buffer|direct]\n", argv[0]);
+               exit(1);
+       }
+       char *file = argv[1];
+       read_count = atoi(argv[2]);
+       int ret = 0,sum = 0, i = 0, fd = -1;
+       if(argc == 4 && strncmp(argv[3], "direct",6) == 0)
+               fd = open(file, O_RDONLY|O_DIRECT);
+       else
+               fd = open(file, O_RDONLY);
+       
+       while(i++ < read_count){
+               memset(buf, 0, BUFSIZE);
+               ret = read(fd, buf, BUFSIZE-1);
+               if(ret > 0){
+                       write(STDOUT_FILENO, buf, ret);
+                       sum += ret;
+               }else if(ret == 0){
+                       printf("======read end======\n");
+                       break;
+               }else{
+                       printf("error:%d\n", errno);
+                       break;
+               }
+               sleep(1);
+       }
+       printf("======read sum: %d======\n", sum);
+       close(fd);
+       return 0;
+}
diff --git a/tests/test_read_proc.sh b/tests/test_read_proc.sh
new file mode 100755 (executable)
index 0000000..de95c1e
--- /dev/null
@@ -0,0 +1,32 @@
+#/bin/bash
+#./lxcfs -s -f -d -o allow_other -o direct_io /var/lib/lxcfs
+
+red_c() {
+     echo -e $2 "\e[31;1m${1}\e[0m"
+}
+DIR=/var/lib/lxcfs
+
+if ! mountpoint -q $DIR; then
+    echo "lxcfs isn't mounted on /var/lib/lxcfs"
+    exit 1
+fi
+
+
+PWD=`pwd`
+COUNT=3
+
+for i in test-read
+do
+       BIN=$PWD/$i
+
+       red_c "$BIN test cpuinfo"
+       $BIN $DIR/proc/cpuinfo $COUNT
+
+       red_c "$BIN test stat"
+       $BIN $DIR/proc/stat $COUNT
+       
+       red_c "$BIN test meminfo"
+       $BIN $DIR/proc/meminfo $COUNT
+       
+done
+exit 0