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

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
...@@ -119,3 +119,12 @@ Description: ...@@ -119,3 +119,12 @@ Description:
efficiency can be calculated using compr_data_size and this efficiency can be calculated using compr_data_size and this
statistic. statistic.
Unit: bytes 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
...@@ -74,14 +74,30 @@ There is little point creating a zram of greater than twice the size of memory ...@@ -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 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. 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 mkswap /dev/zram0
swapon /dev/zram0 swapon /dev/zram0
mkfs.ext4 /dev/zram1 mkfs.ext4 /dev/zram1
mount /dev/zram1 /tmp mount /dev/zram1 /tmp
6) Stats: 7) Stats:
Per-device statistics are exported as various nodes under Per-device statistics are exported as various nodes under
/sys/block/zram<id>/ /sys/block/zram<id>/
disksize disksize
...@@ -96,11 +112,11 @@ size of the disk when not in use so a huge zram is wasteful. ...@@ -96,11 +112,11 @@ size of the disk when not in use so a huge zram is wasteful.
compr_data_size compr_data_size
mem_used_total mem_used_total
7) Deactivate: 8) Deactivate:
swapoff /dev/zram0 swapoff /dev/zram0
umount /dev/zram1 umount /dev/zram1
8) Reset: 9) Reset:
Write any positive value to 'reset' sysfs node Write any positive value to 'reset' sysfs node
echo 1 > /sys/block/zram0/reset echo 1 > /sys/block/zram0/reset
echo 1 > /sys/block/zram1/reset echo 1 > /sys/block/zram1/reset
......
...@@ -122,6 +122,37 @@ static ssize_t max_comp_streams_show(struct device *dev, ...@@ -122,6 +122,37 @@ static ssize_t max_comp_streams_show(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%d\n", val); 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, static ssize_t max_comp_streams_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len) 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, ...@@ -513,6 +544,14 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
ret = -ENOMEM; ret = -ENOMEM;
goto out; 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); cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_WO);
if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) { if ((clen == PAGE_SIZE) && !is_partial_io(bvec)) {
...@@ -617,6 +656,9 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity) ...@@ -617,6 +656,9 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity)
struct zram_meta *meta; struct zram_meta *meta;
down_write(&zram->init_lock); down_write(&zram->init_lock);
zram->limit_pages = 0;
if (!init_done(zram)) { if (!init_done(zram)) {
up_write(&zram->init_lock); up_write(&zram->init_lock);
return; return;
...@@ -857,6 +899,8 @@ static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL); ...@@ -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(reset, S_IWUSR, NULL, reset_store);
static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL); 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_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, static DEVICE_ATTR(max_comp_streams, S_IRUGO | S_IWUSR,
max_comp_streams_show, max_comp_streams_store); max_comp_streams_show, max_comp_streams_store);
static DEVICE_ATTR(comp_algorithm, S_IRUGO | S_IWUSR, static DEVICE_ATTR(comp_algorithm, S_IRUGO | S_IWUSR,
...@@ -885,6 +929,7 @@ static struct attribute *zram_disk_attrs[] = { ...@@ -885,6 +929,7 @@ static struct attribute *zram_disk_attrs[] = {
&dev_attr_orig_data_size.attr, &dev_attr_orig_data_size.attr,
&dev_attr_compr_data_size.attr, &dev_attr_compr_data_size.attr,
&dev_attr_mem_used_total.attr, &dev_attr_mem_used_total.attr,
&dev_attr_mem_limit.attr,
&dev_attr_max_comp_streams.attr, &dev_attr_max_comp_streams.attr,
&dev_attr_comp_algorithm.attr, &dev_attr_comp_algorithm.attr,
NULL, NULL,
......
...@@ -112,6 +112,11 @@ struct zram { ...@@ -112,6 +112,11 @@ struct zram {
u64 disksize; /* bytes */ u64 disksize; /* bytes */
int max_comp_streams; int max_comp_streams;
struct zram_stats stats; struct zram_stats stats;
/*
* the number of pages zram can consume for storing compressed data
*/
unsigned long limit_pages;
char compressor[10]; char compressor[10];
}; };
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment