[lxc-devel] [RFC] Add support for /proc/swaps

Serge Hallyn serge.hallyn at ubuntu.com
Tue Jan 26 18:45:45 UTC 2016


Quoting Nehal J Wani (nehaljw.kkd1 at gmail.com):
> Built over https://github.com/tssge/lxcfs/commit/50b75e3
> 
> Example Output:
> 
> [root at lxc-dev ~]# lxc-attach -n ubuntuwily --  /bin/cat /proc/swaps
> Filename                                Type            Size    Used    Priority
> none                                    virtual         1048572 1048572 0
> 
> 
> Signed-off-by: Nehal J Wani <nehaljw.kkd1 at gmail.com>

Thanks.  I've not had a chance to test this, but will aim to do so this
week.  Two comments below, if you like I can fix them up myself when I
apply after I test.

> ---
>  lxcfs.c | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 116 insertions(+), 2 deletions(-)
> 
> diff --git a/lxcfs.c b/lxcfs.c
> index a561882..9c52862 100644
> --- a/lxcfs.c
> +++ b/lxcfs.c
> @@ -43,6 +43,7 @@ enum {
>  	LXC_TYPE_PROC_UPTIME,
>  	LXC_TYPE_PROC_STAT,
>  	LXC_TYPE_PROC_DISKSTATS,
> +	LXC_TYPE_PROC_SWAPS,
>  };
>  
>  struct file_info {
> @@ -2394,6 +2395,113 @@ err:
>  	return rv;
>  }
>  
> +static int proc_swaps_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 *cg;
> +	char *memswlimit_str = NULL, *memlimit_str = NULL, *memusage_str = NULL, *memswusage_str = NULL,
> +             *memswlimit_default_str = NULL, *memswusage_default_str = NULL;
> +	unsigned long memswlimit = 0, memlimit = 0, memusage = 0, memswusage = 0, swap_total = 0, swap_free = 0;
> +	size_t total_len = 0, rv = 0, linelen = 0;
> +	char *cache = d->buf;
> +	char *line = NULL;
> +	FILE *f = NULL;
> +
> +	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;
> +	}
> +
> +	cg = get_pid_cgroup(fc->pid, "memory");

This should now find and use the initpid.

> +	if (!cg)
> +		return read_file("/proc/swaps", buf, size, d);
> +
> +	if (!cgfs_get_value("memory", cg, "memory.limit_in_bytes", &memlimit_str))
> +		goto err;
> +
> +	if (!cgfs_get_value("memory", cg, "memory.usage_in_bytes", &memusage_str))
> +		goto err;
> +
> +	memlimit = strtoul(memlimit_str, NULL, 10);
> +	memusage = strtoul(memusage_str, NULL, 10);
> +
> +	if (cgfs_get_value("memory", cg, "memory.memsw.usage_in_bytes", &memswusage_str) &&
> +	    cgfs_get_value("memory", cg, "memory.memsw.limit_in_bytes", &memswlimit_str)) {
> +
> +                /* If swap accounting is turned on, then default value is assumed to be that of cgroup / */
> +                if (!cgfs_get_value("memory", "/", "memory.memsw.limit_in_bytes", &memswlimit_default_str))
> +                    goto err;
> +                if (!cgfs_get_value("memory", "/", "memory.memsw.usage_in_bytes", &memswusage_default_str))
> +                    goto err;
> +
> +		memswlimit = strtoul(memswlimit_str, NULL, 10);
> +		memswusage = strtoul(memswusage_str, NULL, 10);
> +
> +                if (!strcmp(memswlimit_str, memswlimit_default_str))
> +                    memswlimit = 0;
> +                if (!strcmp(memswusage_str, memswusage_default_str))
> +                    memswusage = 0;
> +
> +		swap_total = (memswlimit - memlimit) / 1024;
> +		swap_free = (memswusage - memusage) / 1024;
> +	}
> +
> +	total_len = snprintf(d->buf, d->size, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
> +
> +	/* When no mem + swap limit is specified or swapaccount=0*/
> +	if (!memswlimit) {
> +		f = fopen("/proc/meminfo", "r");
> +		if (!f)
> +			goto err;
> +
> +		while (getline(&line, &linelen, f) != -1) {
> +			if (startswith(line, "SwapTotal:")) {
> +				sscanf(line, "SwapTotal:      %8lu kB", &swap_total);
> +			} else if (startswith(line, "SwapFree:")) {
> +				sscanf(line, "SwapFree:      %8lu kB", &swap_free);
> +			}
> +		}
> +	}
> +
> +	if (swap_total > 0) {
> +		total_len += snprintf(d->buf + total_len, d->size,

Shouldn't this be "d->size - total_len" ?

> +				 "none%*svirtual\t\t%lu\t%lu\t0\n", 36, " ",
> +				 swap_total, swap_free);
> +	}
> +
> +	if (total_len < 0) {
> +		perror("Error writing to cache");
> +		rv = 0;
> +		goto err;
> +	}
> +
> +	d->cached = 1;
> +	d->size = (int)total_len;
> +
> +	if (total_len > size) total_len = size;
> +	memcpy(buf, d->buf, total_len);
> +	rv = total_len;
> +
> +err:
> +	free(cg);
> +	free(memswlimit_str);
> +	free(memlimit_str);
> +	free(memusage_str);
> +	free(memswusage_str);
> +	free(memswusage_default_str);
> +	free(memswlimit_default_str);
> +	return rv;
> +}
> +
>  /*
>   * Read the cpuset.cpus for cg
>   * Return the answer in a newly allocated string which must be freed
> @@ -2956,7 +3064,8 @@ static int proc_getattr(const char *path, struct stat *sb)
>  			strcmp(path, "/proc/cpuinfo") == 0 ||
>  			strcmp(path, "/proc/uptime") == 0 ||
>  			strcmp(path, "/proc/stat") == 0 ||
> -			strcmp(path, "/proc/diskstats") == 0) {
> +			strcmp(path, "/proc/diskstats") == 0 ||
> +			strcmp(path, "/proc/swaps") == 0) {
>  		sb->st_size = 0;
>  		sb->st_mode = S_IFREG | 00444;
>  		sb->st_nlink = 1;
> @@ -2973,7 +3082,8 @@ static int proc_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off
>  				filler(buf, "meminfo", NULL, 0) != 0 ||
>  				filler(buf, "stat", NULL, 0) != 0 ||
>  				filler(buf, "uptime", NULL, 0) != 0 ||
> -				filler(buf, "diskstats", NULL, 0) != 0)
> +				filler(buf, "diskstats", NULL, 0) != 0 ||
> +				filler(buf, "swaps", NULL, 0) != 0)
>  		return -EINVAL;
>  	return 0;
>  }
> @@ -2993,6 +3103,8 @@ static int proc_open(const char *path, struct fuse_file_info *fi)
>  		type = LXC_TYPE_PROC_STAT;
>  	else if (strcmp(path, "/proc/diskstats") == 0)
>  		type = LXC_TYPE_PROC_DISKSTATS;
> +	else if (strcmp(path, "/proc/swaps") == 0)
> +		type = LXC_TYPE_PROC_SWAPS;
>  	if (type == -1)
>  		return -ENOENT;
>  
> @@ -3039,6 +3151,8 @@ static int proc_read(const char *path, char *buf, size_t size, off_t offset,
>  		return proc_stat_read(buf, size, offset, fi);
>  	case LXC_TYPE_PROC_DISKSTATS:
>  		return proc_diskstats_read(buf, size, offset, fi);
> +	case LXC_TYPE_PROC_SWAPS:
> +		return proc_swaps_read(buf, size, offset, fi);
>  	default:
>  		return -EINVAL;
>  	}
> -- 
> 2.5.0
> 


More information about the lxc-devel mailing list