Commit 9ada9da9 authored by Minchan Kim's avatar Minchan Kim Committed by Linus Torvalds
Browse files

zram: zram memory size limitation



Since zram has no control feature to limit memory usage, it makes hard to
manage system memrory.

This patch adds new knob "mem_limit" via sysfs to set up the a limit so
that zram could fail allocation once it reaches the limit.

In addition, user could change the limit in runtime so that he could
manage the memory more dynamically.

Initial state is no limit so it doesn't break old behavior.

[akpm@linux-foundation.org: fix typo, per Sergey]
Signed-off-by: default avatarMinchan Kim <minchan@kernel.org>
Cc: Dan Streetman <ddstreet@ieee.org>
Cc: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Jerome Marchand <jmarchan@redhat.com>
Cc: <juno.choi@lge.com>
Cc: <seungho1.park@lge.com>
Cc: Luigi Semenzato <semenzato@google.com>
Cc: Nitin Gupta <ngupta@vflare.org>
Cc: Seth Jennings <sjennings@variantweb.net>
Cc: David Horner <ds2horner@gmail.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Minchan Kim <minchan@kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 722cdc17
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -119,3 +119,12 @@ Description:
		efficiency can be calculated using compr_data_size and this
		statistic.
		Unit: bytes

What:		/sys/block/zram<id>/mem_limit
Date:		August 2014
Contact:	Minchan Kim <minchan@kernel.org>
Description:
		The mem_limit file is read/write and specifies the maximum
		amount of memory ZRAM can use to store the compressed data.  The
		limit could be changed in run time and "0" means disable the
		limit.  No limit is the initial state.  Unit: bytes
+20 −4
Original line number Diff line number Diff line
@@ -74,14 +74,30 @@ There is little point creating a zram of greater than twice the size of memory
since we expect a 2:1 compression ratio. Note that zram uses about 0.1% of the
size of the disk when not in use so a huge zram is wasteful.

5) Activate:
5) Set memory limit: Optional
	Set memory limit by writing the value to sysfs node 'mem_limit'.
	The value can be either in bytes or you can use mem suffixes.
	In addition, you could change the value in runtime.
	Examples:
	    # limit /dev/zram0 with 50MB memory
	    echo $((50*1024*1024)) > /sys/block/zram0/mem_limit

	    # Using mem suffixes
	    echo 256K > /sys/block/zram0/mem_limit
	    echo 512M > /sys/block/zram0/mem_limit
	    echo 1G > /sys/block/zram0/mem_limit

	    # To disable memory limit
	    echo 0 > /sys/block/zram0/mem_limit

6) Activate:
	mkswap /dev/zram0
	swapon /dev/zram0

	mkfs.ext4 /dev/zram1
	mount /dev/zram1 /tmp

6) Stats:
7) Stats:
	Per-device statistics are exported as various nodes under
	/sys/block/zram<id>/
		disksize
@@ -96,11 +112,11 @@ size of the disk when not in use so a huge zram is wasteful.
		compr_data_size
		mem_used_total

7) Deactivate:
8) Deactivate:
	swapoff /dev/zram0
	umount /dev/zram1

8) Reset:
9) Reset:
	Write any positive value to 'reset' sysfs node
	echo 1 > /sys/block/zram0/reset
	echo 1 > /sys/block/zram1/reset
+45 −0
Original line number Diff line number Diff line
@@ -122,6 +122,37 @@ static ssize_t max_comp_streams_show(struct device *dev,
	return scnprintf(buf, PAGE_SIZE, "%d\n", val);
}

static ssize_t mem_limit_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	u64 val;
	struct zram *zram = dev_to_zram(dev);

	down_read(&zram->init_lock);
	val = zram->limit_pages;
	up_read(&zram->init_lock);

	return scnprintf(buf, PAGE_SIZE, "%llu\n", val << PAGE_SHIFT);
}

static ssize_t mem_limit_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t len)
{
	u64 limit;
	char *tmp;
	struct zram *zram = dev_to_zram(dev);

	limit = memparse(buf, &tmp);
	if (buf == tmp) /* no chars parsed, invalid input */
		return -EINVAL;

	down_write(&zram->init_lock);
	zram->limit_pages = PAGE_ALIGN(limit) >> PAGE_SHIFT;
	up_write(&zram->init_lock);

	return len;
}

static ssize_t max_comp_streams_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t len)
{
@@ -513,6 +544,14 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
		ret = -ENOMEM;
		goto out;
	}

	if (zram->limit_pages &&
		zs_get_total_pages(meta->mem_pool) > zram->limit_pages) {
		zs_free(meta->mem_pool, handle);
		ret = -ENOMEM;
		goto out;
	}

	cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_WO);

	if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) {
@@ -617,6 +656,9 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity)
	struct zram_meta *meta;

	down_write(&zram->init_lock);

	zram->limit_pages = 0;

	if (!init_done(zram)) {
		up_write(&zram->init_lock);
		return;
@@ -857,6 +899,8 @@ static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL);
static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL);
static DEVICE_ATTR(mem_limit, S_IRUGO | S_IWUSR, mem_limit_show,
		mem_limit_store);
static DEVICE_ATTR(max_comp_streams, S_IRUGO | S_IWUSR,
		max_comp_streams_show, max_comp_streams_store);
static DEVICE_ATTR(comp_algorithm, S_IRUGO | S_IWUSR,
@@ -885,6 +929,7 @@ static struct attribute *zram_disk_attrs[] = {
	&dev_attr_orig_data_size.attr,
	&dev_attr_compr_data_size.attr,
	&dev_attr_mem_used_total.attr,
	&dev_attr_mem_limit.attr,
	&dev_attr_max_comp_streams.attr,
	&dev_attr_comp_algorithm.attr,
	NULL,
+5 −0
Original line number Diff line number Diff line
@@ -112,6 +112,11 @@ struct zram {
	u64 disksize;	/* bytes */
	int max_comp_streams;
	struct zram_stats stats;
	/*
	 * the number of pages zram can consume for storing compressed data
	 */
	unsigned long limit_pages;

	char compressor[10];
};
#endif