From 97f1f27b88a28081cf52e728cb41956cbc13f489 Mon Sep 17 00:00:00 2001 From: Ye Yin Date: Thu, 9 Apr 2015 19:01:10 +0800 Subject: [PATCH] add cache for proc file, for support multiple read Signed-off-by: Ye Yin --- Makefile.am | 5 + lxcfs.c | 200 +++++++++++++++++++++++++++++++++------- tests/test-read.c | 47 ++++++++++ tests/test_read_proc.sh | 32 +++++++ 4 files changed, 251 insertions(+), 33 deletions(-) create mode 100644 tests/test-read.c create mode 100755 tests/test_read_proc.sh diff --git a/Makefile.am b/Makefile.am index b083b0a..7b690e2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 84c1045..2ec471d 100644 --- 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 index 0000000..4c96a57 --- /dev/null +++ b/tests/test-read.c @@ -0,0 +1,47 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFSIZE 1025 +char buf[BUFSIZE]; + +int read_count = 2; + +int main(int argc, char *argv[]){ + if(argc < 3){ + fprintf(stderr, "usage: %s [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 index 0000000..de95c1e --- /dev/null +++ b/tests/test_read_proc.sh @@ -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 -- 2.39.5