summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDongwoo Lee <dwoo08.lee@samsung.com>2020-06-04 13:54:35 +0900
committerDongwoo Lee <dwoo08.lee@samsung.com>2020-06-15 18:02:02 +0900
commitf59ab8a996983099adafa8e8dcc861f1af4d7471 (patch)
tree4257f4317aa8ced4957c169e99ae540a63b57462
parent62d27fa223c759643005c3933edc487548593f29 (diff)
downloadlinux-4.9-exynos9110-f59ab8a996983099adafa8e8dcc861f1af4d7471.tar.gz
linux-4.9-exynos9110-f59ab8a996983099adafa8e8dcc861f1af4d7471.tar.bz2
linux-4.9-exynos9110-f59ab8a996983099adafa8e8dcc861f1af4d7471.zip
block: zram: Add support for dynamic compressor switch
Orginally, the compression algorithm cannot be changed until resetting it if zram is once initialized by setting disksize. Since this, however, zram can have multiple compressor and switch them dynamically. With this, zram uses the algorithm which is fast but has low compression ratio at first, and can change to the one that is slightly slower but having higher ratio when the target get bothered by low memory. Change-Id: Icf9ac074b340122532a10d4e28fd0c182dbcc8a9 Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
-rw-r--r--drivers/block/zram/zcomp.c94
-rw-r--r--drivers/block/zram/zcomp.h6
-rw-r--r--drivers/block/zram/zram_drv.c58
-rw-r--r--drivers/block/zram/zram_drv.h3
4 files changed, 103 insertions, 58 deletions
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index c084a7f9763d..5baac162f118 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -69,26 +69,6 @@ static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp)
return zstrm;
}
-bool zcomp_available_algorithm(const char *comp)
-{
- int i = 0;
-
- while (backends[i]) {
- if (sysfs_streq(comp, backends[i]))
- return true;
- i++;
- }
-
- /*
- * Crypto does not ignore a trailing new line symbol,
- * so make sure you don't supply a string containing
- * one.
- * This also means that we permit zcomp initialisation
- * with any compressing algorithm known to crypto api.
- */
- return crypto_has_comp(comp, 0, 0) == 1;
-}
-
/* show available compressors */
ssize_t zcomp_available_show(const char *comp, char *buf)
{
@@ -229,7 +209,7 @@ cleanup:
return -ENOMEM;
}
-void zcomp_destroy(struct zcomp *comp)
+static void zcomp_destroy(struct zcomp *comp)
{
unsigned long cpu;
@@ -243,22 +223,40 @@ void zcomp_destroy(struct zcomp *comp)
kfree(comp);
}
+void zcomp_reset(struct list_head *blist)
+{
+ struct list_head *curr, *next;
+ struct zcomp *comp;
+ int i;
+
+ list_for_each_safe(curr, next, blist) {
+ comp = list_entry(curr, struct zcomp, list);
+ list_del(&comp->list);
+
+ for (i = 0; backends[i]; i++) {
+ if (sysfs_streq(comp->name, backends[i]))
+ break;
+ }
+
+ if (!backends[i])
+ kfree(comp->name);
+
+ zcomp_destroy(comp);
+ }
+}
+
/*
- * search available compressors for requested algorithm.
* allocate new zcomp and initialize it. return compressing
* backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL)
* if requested algorithm is not supported, ERR_PTR(-ENOMEM) in
* case of allocation error, or any other error potentially
* returned by zcomp_init().
*/
-struct zcomp *zcomp_create(const char *compress)
+static struct zcomp *zcomp_create(const char *compress)
{
struct zcomp *comp;
int error;
- if (!zcomp_available_algorithm(compress))
- return ERR_PTR(-EINVAL);
-
comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
if (!comp)
return ERR_PTR(-ENOMEM);
@@ -271,3 +269,47 @@ struct zcomp *zcomp_create(const char *compress)
}
return comp;
}
+
+struct zcomp *zcomp_get_instance(struct list_head *blist, const char *name)
+{
+ struct zcomp *comp;
+ const char *comp_name = NULL;
+ int i;
+
+ list_for_each_entry(comp, blist, list)
+ if (sysfs_streq(name, comp->name))
+ return comp;
+
+ for (i = 0; backends[i]; i++) {
+ if (sysfs_streq(name, backends[i])) {
+ comp_name = backends[i];
+ break;
+ }
+ }
+
+ if (!comp_name) {
+ /*
+ * Crypto does not ignore a trailing new line symbol,
+ * so make sure you don't supply a string containing
+ * one.
+ * This also means that we permit zcomp initialisation
+ * with any compressing algorithm known to crypto api.
+ */
+ if (crypto_has_comp(name, 0, 0) == 1)
+ comp_name = kstrdup(name, GFP_KERNEL);
+ else
+ return ERR_PTR(-ENOENT);
+ }
+
+ comp = zcomp_create(comp_name);
+ if (IS_ERR(comp)) {
+ pr_err("Cannot initialise %s compressing backend\n", name);
+ if (!backends[i])
+ kfree(comp_name);
+ return comp;
+ }
+
+ list_add(&comp->list, blist);
+
+ return comp;
+}
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index 478cac2ed465..8eb633decf7d 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -22,13 +22,13 @@ struct zcomp {
struct notifier_block notifier;
const char *name;
+ struct list_head list;
};
ssize_t zcomp_available_show(const char *comp, char *buf);
-bool zcomp_available_algorithm(const char *comp);
-struct zcomp *zcomp_create(const char *comp);
-void zcomp_destroy(struct zcomp *comp);
+struct zcomp *zcomp_get_instance(struct list_head *blist, const char *name);
+void zcomp_reset(struct list_head *blist);
struct zcomp_strm *zcomp_stream_get(struct zcomp *comp);
void zcomp_stream_put(struct zcomp *comp);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index c9914d653968..a133568d45b7 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -351,6 +351,7 @@ static ssize_t comp_algorithm_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct zram *zram = dev_to_zram(dev);
+ struct zcomp *comp;
char compressor[CRYPTO_MAX_ALG_NAME];
size_t sz;
@@ -360,16 +361,12 @@ static ssize_t comp_algorithm_store(struct device *dev,
if (sz > 0 && compressor[sz - 1] == '\n')
compressor[sz - 1] = 0x00;
- if (!zcomp_available_algorithm(compressor))
+ comp = zcomp_get_instance(&zram->backend_list, compressor);
+ if (IS_ERR_OR_NULL(comp))
return -EINVAL;
down_write(&zram->init_lock);
- if (init_done(zram)) {
- up_write(&zram->init_lock);
- pr_info("Can't change algorithm for initialized device\n");
- return -EBUSY;
- }
-
+ zram->comp = comp;
strlcpy(zram->compressor, compressor, sizeof(compressor));
up_write(&zram->init_lock);
return len;
@@ -573,12 +570,14 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
int ret = 0;
unsigned char *cmem;
struct zram_meta *meta = zram->meta;
+ struct zcomp *comp;
unsigned long handle;
unsigned int size;
bit_spin_lock(ZRAM_ACCESS, &meta->table[index].value);
handle = meta->table[index].handle;
size = zram_get_obj_size(meta, index);
+ comp = meta->table[index].comp;
if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
@@ -590,10 +589,10 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
if (size == PAGE_SIZE) {
memcpy(mem, cmem, PAGE_SIZE);
} else {
- struct zcomp_strm *zstrm = zcomp_stream_get(zram->comp);
+ struct zcomp_strm *zstrm = zcomp_stream_get(comp);
ret = zcomp_decompress(zstrm, cmem, size, mem);
- zcomp_stream_put(zram->comp);
+ zcomp_stream_put(comp);
}
zs_unmap_object(meta->mem_pool, handle);
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
@@ -665,6 +664,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
unsigned long handle = 0;
struct page *page;
unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
+ struct zcomp *comp;
struct zram_meta *meta = zram->meta;
struct zcomp_strm *zstrm = NULL;
unsigned long alloced_pages;
@@ -710,7 +710,8 @@ compress_again:
goto out;
}
- zstrm = zcomp_stream_get(zram->comp);
+ comp = zram->comp;
+ zstrm = zcomp_stream_get(comp);
ret = zcomp_compress(zstrm, uncmem, &clen);
if (!is_partial_io(bvec)) {
kunmap_atomic(user_mem);
@@ -786,7 +787,7 @@ compress_again:
memcpy(cmem, src, clen);
}
- zcomp_stream_put(zram->comp);
+ zcomp_stream_put(comp);
zstrm = NULL;
zs_unmap_object(meta->mem_pool, handle);
@@ -798,6 +799,7 @@ compress_again:
zram_free_page(zram, index);
meta->table[index].handle = handle;
+ meta->table[index].comp = comp;
zram_set_obj_size(meta, index, clen);
bit_spin_unlock(ZRAM_ACCESS, &meta->table[index].value);
@@ -806,7 +808,7 @@ compress_again:
atomic64_inc(&zram->stats.pages_stored);
out:
if (zstrm)
- zcomp_stream_put(zram->comp);
+ zcomp_stream_put(comp);
if (is_partial_io(bvec))
kfree(uncmem);
return ret;
@@ -1024,7 +1026,6 @@ out:
static void zram_reset_device(struct zram *zram)
{
struct zram_meta *meta;
- struct zcomp *comp;
u64 disksize;
down_write(&zram->init_lock);
@@ -1037,7 +1038,6 @@ static void zram_reset_device(struct zram *zram)
}
meta = zram->meta;
- comp = zram->comp;
disksize = zram->disksize;
/*
* Refcount will go down to 0 eventually and r/w handler
@@ -1061,7 +1061,9 @@ static void zram_reset_device(struct zram *zram)
up_write(&zram->init_lock);
/* I/O operation under all of CPU are done so let's free */
zram_meta_free(meta, disksize);
- zcomp_destroy(comp);
+
+ zram->comp = NULL;
+ zcomp_reset(&zram->backend_list);
}
static ssize_t disksize_store(struct device *dev,
@@ -1073,6 +1075,14 @@ static ssize_t disksize_store(struct device *dev,
struct zram *zram = dev_to_zram(dev);
int err;
+ down_write(&zram->init_lock);
+ if (init_done(zram)) {
+ pr_info("Cannot change disksize for initialized device\n");
+ up_write(&zram->init_lock);
+ return -EBUSY;
+ }
+ up_write(&zram->init_lock);
+
disksize = memparse(buf, NULL);
if (!disksize)
return -EINVAL;
@@ -1082,21 +1092,13 @@ static ssize_t disksize_store(struct device *dev,
if (!meta)
return -ENOMEM;
- comp = zcomp_create(zram->compressor);
- if (IS_ERR(comp)) {
- pr_err("Cannot initialise %s compressing backend\n",
- zram->compressor);
+ comp = zcomp_get_instance(&zram->backend_list, zram->compressor);
+ if (IS_ERR_OR_NULL(comp)) {
err = PTR_ERR(comp);
goto out_free_meta;
}
down_write(&zram->init_lock);
- if (init_done(zram)) {
- pr_info("Cannot change disksize for initialized device\n");
- err = -EBUSY;
- goto out_destroy_comp;
- }
-
init_waitqueue_head(&zram->io_done);
atomic_set(&zram->refcount, 1);
zram->meta = meta;
@@ -1107,10 +1109,6 @@ static ssize_t disksize_store(struct device *dev,
up_write(&zram->init_lock);
return len;
-
-out_destroy_comp:
- up_write(&zram->init_lock);
- zcomp_destroy(comp);
out_free_meta:
zram_meta_free(meta, disksize);
return err;
@@ -1311,6 +1309,8 @@ static int zram_add(void)
goto out_free_disk;
}
strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor));
+ INIT_LIST_HEAD(&zram->backend_list);
+
zram->meta = NULL;
pr_info("Added device: %s\n", zram->disk->disk_name);
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index 74fcf10da374..be5f3c315350 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -73,6 +73,7 @@ enum zram_pageflags {
struct zram_table_entry {
unsigned long handle;
unsigned long value;
+ struct zcomp *comp;
};
struct zram_stats {
@@ -119,5 +120,7 @@ struct zram {
* zram is claimed so open request will be failed
*/
bool claim; /* Protected by bdev->bd_mutex */
+
+ struct list_head backend_list;
};
#endif