mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-03-18 05:04:04 +00:00
staging: zcache: crypto API support
This patch allow zcache to use the crypto API for page compression. It replaces the direct LZO compress/decompress calls with calls into the crypto compression API. The compressor to be used is specified in the kernel boot line with the zcache parameter like: zcache=lzo or zcache=deflate. If the specified compressor can't be loaded, zcache uses lzo as the default compressor. Signed-off-by: Seth Jennings <sjenning@linux.vnet.ibm.com> Acked-by: Dan Magenheimer <dan.magenheimer@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
af9584b82d
commit
17dd9f831a
2 changed files with 126 additions and 31 deletions
|
@ -1,13 +1,12 @@
|
||||||
config ZCACHE
|
config ZCACHE
|
||||||
tristate "Dynamic compression of swap pages and clean pagecache pages"
|
tristate "Dynamic compression of swap pages and clean pagecache pages"
|
||||||
depends on CLEANCACHE || FRONTSWAP
|
depends on (CLEANCACHE || FRONTSWAP) && CRYPTO
|
||||||
select XVMALLOC
|
select XVMALLOC
|
||||||
select LZO_COMPRESS
|
select CRYPTO_LZO
|
||||||
select LZO_DECOMPRESS
|
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
Zcache doubles RAM efficiency while providing a significant
|
Zcache doubles RAM efficiency while providing a significant
|
||||||
performance boosts on many workloads. Zcache uses lzo1x
|
performance boosts on many workloads. Zcache uses
|
||||||
compression and an in-kernel implementation of transcendent
|
compression and an in-kernel implementation of transcendent
|
||||||
memory to store clean page cache pages and swap in RAM,
|
memory to store clean page cache pages and swap in RAM,
|
||||||
providing a noticeable reduction in disk I/O.
|
providing a noticeable reduction in disk I/O.
|
||||||
|
|
|
@ -6,7 +6,8 @@
|
||||||
*
|
*
|
||||||
* Zcache provides an in-kernel "host implementation" for transcendent memory
|
* Zcache provides an in-kernel "host implementation" for transcendent memory
|
||||||
* and, thus indirectly, for cleancache and frontswap. Zcache includes two
|
* and, thus indirectly, for cleancache and frontswap. Zcache includes two
|
||||||
* page-accessible memory [1] interfaces, both utilizing lzo1x compression:
|
* page-accessible memory [1] interfaces, both utilizing the crypto compression
|
||||||
|
* API:
|
||||||
* 1) "compression buddies" ("zbud") is used for ephemeral pages
|
* 1) "compression buddies" ("zbud") is used for ephemeral pages
|
||||||
* 2) xvmalloc is used for persistent pages.
|
* 2) xvmalloc is used for persistent pages.
|
||||||
* Xvmalloc (based on the TLSF allocator) has very low fragmentation
|
* Xvmalloc (based on the TLSF allocator) has very low fragmentation
|
||||||
|
@ -23,12 +24,13 @@
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
#include <linux/highmem.h>
|
#include <linux/highmem.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/lzo.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/atomic.h>
|
#include <linux/atomic.h>
|
||||||
#include <linux/math64.h>
|
#include <linux/math64.h>
|
||||||
|
#include <linux/crypto.h>
|
||||||
|
#include <linux/string.h>
|
||||||
#include "tmem.h"
|
#include "tmem.h"
|
||||||
|
|
||||||
#include "../zram/xvmalloc.h" /* if built in drivers/staging */
|
#include "../zram/xvmalloc.h" /* if built in drivers/staging */
|
||||||
|
@ -81,6 +83,38 @@ static inline bool is_local_client(struct zcache_client *cli)
|
||||||
return cli == &zcache_host;
|
return cli == &zcache_host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* crypto API for zcache */
|
||||||
|
#define ZCACHE_COMP_NAME_SZ CRYPTO_MAX_ALG_NAME
|
||||||
|
static char zcache_comp_name[ZCACHE_COMP_NAME_SZ];
|
||||||
|
static struct crypto_comp * __percpu *zcache_comp_pcpu_tfms;
|
||||||
|
|
||||||
|
enum comp_op {
|
||||||
|
ZCACHE_COMPOP_COMPRESS,
|
||||||
|
ZCACHE_COMPOP_DECOMPRESS
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline int zcache_comp_op(enum comp_op op,
|
||||||
|
const u8 *src, unsigned int slen,
|
||||||
|
u8 *dst, unsigned int *dlen)
|
||||||
|
{
|
||||||
|
struct crypto_comp *tfm;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
BUG_ON(!zcache_comp_pcpu_tfms);
|
||||||
|
tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, get_cpu());
|
||||||
|
BUG_ON(!tfm);
|
||||||
|
switch (op) {
|
||||||
|
case ZCACHE_COMPOP_COMPRESS:
|
||||||
|
ret = crypto_comp_compress(tfm, src, slen, dst, dlen);
|
||||||
|
break;
|
||||||
|
case ZCACHE_COMPOP_DECOMPRESS:
|
||||||
|
ret = crypto_comp_decompress(tfm, src, slen, dst, dlen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
put_cpu();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**********
|
/**********
|
||||||
* Compression buddies ("zbud") provides for packing two (or, possibly
|
* Compression buddies ("zbud") provides for packing two (or, possibly
|
||||||
* in the future, more) compressed ephemeral pages into a single "raw"
|
* in the future, more) compressed ephemeral pages into a single "raw"
|
||||||
|
@ -408,7 +442,7 @@ static int zbud_decompress(struct page *page, struct zbud_hdr *zh)
|
||||||
{
|
{
|
||||||
struct zbud_page *zbpg;
|
struct zbud_page *zbpg;
|
||||||
unsigned budnum = zbud_budnum(zh);
|
unsigned budnum = zbud_budnum(zh);
|
||||||
size_t out_len = PAGE_SIZE;
|
unsigned int out_len = PAGE_SIZE;
|
||||||
char *to_va, *from_va;
|
char *to_va, *from_va;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -425,8 +459,9 @@ static int zbud_decompress(struct page *page, struct zbud_hdr *zh)
|
||||||
to_va = kmap_atomic(page, KM_USER0);
|
to_va = kmap_atomic(page, KM_USER0);
|
||||||
size = zh->size;
|
size = zh->size;
|
||||||
from_va = zbud_data(zh, size);
|
from_va = zbud_data(zh, size);
|
||||||
ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len);
|
ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, from_va, size,
|
||||||
BUG_ON(ret != LZO_E_OK);
|
to_va, &out_len);
|
||||||
|
BUG_ON(ret);
|
||||||
BUG_ON(out_len != PAGE_SIZE);
|
BUG_ON(out_len != PAGE_SIZE);
|
||||||
kunmap_atomic(to_va, KM_USER0);
|
kunmap_atomic(to_va, KM_USER0);
|
||||||
out:
|
out:
|
||||||
|
@ -624,7 +659,7 @@ static int zbud_show_cumul_chunk_counts(char *buf)
|
||||||
|
|
||||||
/**********
|
/**********
|
||||||
* This "zv" PAM implementation combines the TLSF-based xvMalloc
|
* This "zv" PAM implementation combines the TLSF-based xvMalloc
|
||||||
* with lzo1x compression to maximize the amount of data that can
|
* with the crypto compression API to maximize the amount of data that can
|
||||||
* be packed into a physical page.
|
* be packed into a physical page.
|
||||||
*
|
*
|
||||||
* Zv represents a PAM page with the index and object (plus a "size" value
|
* Zv represents a PAM page with the index and object (plus a "size" value
|
||||||
|
@ -711,7 +746,7 @@ static void zv_free(struct xv_pool *xvpool, struct zv_hdr *zv)
|
||||||
|
|
||||||
static void zv_decompress(struct page *page, struct zv_hdr *zv)
|
static void zv_decompress(struct page *page, struct zv_hdr *zv)
|
||||||
{
|
{
|
||||||
size_t clen = PAGE_SIZE;
|
unsigned int clen = PAGE_SIZE;
|
||||||
char *to_va;
|
char *to_va;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -720,10 +755,10 @@ static void zv_decompress(struct page *page, struct zv_hdr *zv)
|
||||||
size = xv_get_object_size(zv) - sizeof(*zv);
|
size = xv_get_object_size(zv) - sizeof(*zv);
|
||||||
BUG_ON(size == 0);
|
BUG_ON(size == 0);
|
||||||
to_va = kmap_atomic(page, KM_USER0);
|
to_va = kmap_atomic(page, KM_USER0);
|
||||||
ret = lzo1x_decompress_safe((char *)zv + sizeof(*zv),
|
ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, (char *)zv + sizeof(*zv),
|
||||||
size, to_va, &clen);
|
size, to_va, &clen);
|
||||||
kunmap_atomic(to_va, KM_USER0);
|
kunmap_atomic(to_va, KM_USER0);
|
||||||
BUG_ON(ret != LZO_E_OK);
|
BUG_ON(ret);
|
||||||
BUG_ON(clen != PAGE_SIZE);
|
BUG_ON(clen != PAGE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1286,25 +1321,24 @@ static struct tmem_pamops zcache_pamops = {
|
||||||
* zcache compression/decompression and related per-cpu stuff
|
* zcache compression/decompression and related per-cpu stuff
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LZO_WORKMEM_BYTES LZO1X_1_MEM_COMPRESS
|
|
||||||
#define LZO_DSTMEM_PAGE_ORDER 1
|
|
||||||
static DEFINE_PER_CPU(unsigned char *, zcache_workmem);
|
|
||||||
static DEFINE_PER_CPU(unsigned char *, zcache_dstmem);
|
static DEFINE_PER_CPU(unsigned char *, zcache_dstmem);
|
||||||
|
#define ZCACHE_DSTMEM_ORDER 1
|
||||||
|
|
||||||
static int zcache_compress(struct page *from, void **out_va, size_t *out_len)
|
static int zcache_compress(struct page *from, void **out_va, size_t *out_len)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
unsigned char *dmem = __get_cpu_var(zcache_dstmem);
|
unsigned char *dmem = __get_cpu_var(zcache_dstmem);
|
||||||
unsigned char *wmem = __get_cpu_var(zcache_workmem);
|
|
||||||
char *from_va;
|
char *from_va;
|
||||||
|
|
||||||
BUG_ON(!irqs_disabled());
|
BUG_ON(!irqs_disabled());
|
||||||
if (unlikely(dmem == NULL || wmem == NULL))
|
if (unlikely(dmem == NULL))
|
||||||
goto out; /* no buffer, so can't compress */
|
goto out; /* no buffer or no compressor so can't compress */
|
||||||
|
*out_len = PAGE_SIZE << ZCACHE_DSTMEM_ORDER;
|
||||||
from_va = kmap_atomic(from, KM_USER0);
|
from_va = kmap_atomic(from, KM_USER0);
|
||||||
mb();
|
mb();
|
||||||
ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem);
|
ret = zcache_comp_op(ZCACHE_COMPOP_COMPRESS, from_va, PAGE_SIZE, dmem,
|
||||||
BUG_ON(ret != LZO_E_OK);
|
(unsigned int *)out_len);
|
||||||
|
BUG_ON(ret);
|
||||||
*out_va = dmem;
|
*out_va = dmem;
|
||||||
kunmap_atomic(from_va, KM_USER0);
|
kunmap_atomic(from_va, KM_USER0);
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
@ -1312,29 +1346,48 @@ out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int zcache_comp_cpu_up(int cpu)
|
||||||
|
{
|
||||||
|
struct crypto_comp *tfm;
|
||||||
|
|
||||||
|
tfm = crypto_alloc_comp(zcache_comp_name, 0, 0);
|
||||||
|
if (IS_ERR(tfm))
|
||||||
|
return NOTIFY_BAD;
|
||||||
|
*per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = tfm;
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zcache_comp_cpu_down(int cpu)
|
||||||
|
{
|
||||||
|
struct crypto_comp *tfm;
|
||||||
|
|
||||||
|
tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu);
|
||||||
|
crypto_free_comp(tfm);
|
||||||
|
*per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int zcache_cpu_notifier(struct notifier_block *nb,
|
static int zcache_cpu_notifier(struct notifier_block *nb,
|
||||||
unsigned long action, void *pcpu)
|
unsigned long action, void *pcpu)
|
||||||
{
|
{
|
||||||
int cpu = (long)pcpu;
|
int ret, cpu = (long)pcpu;
|
||||||
struct zcache_preload *kp;
|
struct zcache_preload *kp;
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case CPU_UP_PREPARE:
|
case CPU_UP_PREPARE:
|
||||||
|
ret = zcache_comp_cpu_up(cpu);
|
||||||
|
if (ret != NOTIFY_OK) {
|
||||||
|
pr_err("zcache: can't allocate compressor transform\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages(
|
per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages(
|
||||||
GFP_KERNEL | __GFP_REPEAT,
|
GFP_KERNEL | __GFP_REPEAT, ZCACHE_DSTMEM_ORDER);
|
||||||
LZO_DSTMEM_PAGE_ORDER),
|
|
||||||
per_cpu(zcache_workmem, cpu) =
|
|
||||||
kzalloc(LZO1X_MEM_COMPRESS,
|
|
||||||
GFP_KERNEL | __GFP_REPEAT);
|
|
||||||
break;
|
break;
|
||||||
case CPU_DEAD:
|
case CPU_DEAD:
|
||||||
case CPU_UP_CANCELED:
|
case CPU_UP_CANCELED:
|
||||||
|
zcache_comp_cpu_down(cpu);
|
||||||
free_pages((unsigned long)per_cpu(zcache_dstmem, cpu),
|
free_pages((unsigned long)per_cpu(zcache_dstmem, cpu),
|
||||||
LZO_DSTMEM_PAGE_ORDER);
|
ZCACHE_DSTMEM_ORDER);
|
||||||
per_cpu(zcache_dstmem, cpu) = NULL;
|
per_cpu(zcache_dstmem, cpu) = NULL;
|
||||||
kfree(per_cpu(zcache_workmem, cpu));
|
|
||||||
per_cpu(zcache_workmem, cpu) = NULL;
|
|
||||||
kp = &per_cpu(zcache_preloads, cpu);
|
kp = &per_cpu(zcache_preloads, cpu);
|
||||||
while (kp->nr) {
|
while (kp->nr) {
|
||||||
kmem_cache_free(zcache_objnode_cache,
|
kmem_cache_free(zcache_objnode_cache,
|
||||||
|
@ -1919,6 +1972,44 @@ static int __init no_frontswap(char *s)
|
||||||
|
|
||||||
__setup("nofrontswap", no_frontswap);
|
__setup("nofrontswap", no_frontswap);
|
||||||
|
|
||||||
|
static int __init enable_zcache_compressor(char *s)
|
||||||
|
{
|
||||||
|
strncpy(zcache_comp_name, s, ZCACHE_COMP_NAME_SZ);
|
||||||
|
zcache_enabled = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
__setup("zcache=", enable_zcache_compressor);
|
||||||
|
|
||||||
|
|
||||||
|
static int zcache_comp_init(void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/* check crypto algorithm */
|
||||||
|
if (*zcache_comp_name != '\0') {
|
||||||
|
ret = crypto_has_comp(zcache_comp_name, 0, 0);
|
||||||
|
if (!ret)
|
||||||
|
pr_info("zcache: %s not supported\n",
|
||||||
|
zcache_comp_name);
|
||||||
|
}
|
||||||
|
if (!ret)
|
||||||
|
strcpy(zcache_comp_name, "lzo");
|
||||||
|
ret = crypto_has_comp(zcache_comp_name, 0, 0);
|
||||||
|
if (!ret) {
|
||||||
|
ret = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pr_info("zcache: using %s compressor\n", zcache_comp_name);
|
||||||
|
|
||||||
|
/* alloc percpu transforms */
|
||||||
|
ret = 0;
|
||||||
|
zcache_comp_pcpu_tfms = alloc_percpu(struct crypto_comp *);
|
||||||
|
if (!zcache_comp_pcpu_tfms)
|
||||||
|
ret = 1;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init zcache_init(void)
|
static int __init zcache_init(void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -1941,6 +2032,11 @@ static int __init zcache_init(void)
|
||||||
pr_err("zcache: can't register cpu notifier\n");
|
pr_err("zcache: can't register cpu notifier\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
ret = zcache_comp_init();
|
||||||
|
if (ret) {
|
||||||
|
pr_err("zcache: compressor initialization failed\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
for_each_online_cpu(cpu) {
|
for_each_online_cpu(cpu) {
|
||||||
void *pcpu = (void *)(long)cpu;
|
void *pcpu = (void *)(long)cpu;
|
||||||
zcache_cpu_notifier(&zcache_cpu_notifier_block,
|
zcache_cpu_notifier(&zcache_cpu_notifier_block,
|
||||||
|
|
Loading…
Add table
Reference in a new issue