Also this one: https://lkml.org/lkml/2012/1/3/263 Bigger change, might be a merge-window sized commit. Also Acked by Dan: https://lkml.org/lkml/2012/1/4/240 Thanks -- Seth On 01/03/2012 04:31 PM, Seth Jennings wrote: > 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@xxxxxxxxxxxxxxxxxx> > --- > drivers/staging/zcache/Kconfig | 7 +- > drivers/staging/zcache/zcache-main.c | 150 ++++++++++++++++++++++++++++------ > 2 files changed, 126 insertions(+), 31 deletions(-) > > diff --git a/drivers/staging/zcache/Kconfig b/drivers/staging/zcache/Kconfig > index 7fabcb2..1b7bba7 100644 > --- a/drivers/staging/zcache/Kconfig > +++ b/drivers/staging/zcache/Kconfig > @@ -1,13 +1,12 @@ > config ZCACHE > tristate "Dynamic compression of swap pages and clean pagecache pages" > - depends on CLEANCACHE || FRONTSWAP > + depends on (CLEANCACHE || FRONTSWAP) && CRYPTO > select XVMALLOC > - select LZO_COMPRESS > - select LZO_DECOMPRESS > + select CRYPTO_LZO > default n > help > 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 > memory to store clean page cache pages and swap in RAM, > providing a noticeable reduction in disk I/O. > diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c > index 56c1f9c..a4384eb 100644 > --- a/drivers/staging/zcache/zcache-main.c > +++ b/drivers/staging/zcache/zcache-main.c > @@ -6,7 +6,8 @@ > * > * Zcache provides an in-kernel "host implementation" for transcendent memory > * 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 > * 2) xvmalloc is used for persistent pages. > * Xvmalloc (based on the TLSF allocator) has very low fragmentation > @@ -23,12 +24,13 @@ > #include <linux/cpu.h> > #include <linux/highmem.h> > #include <linux/list.h> > -#include <linux/lzo.h> > #include <linux/slab.h> > #include <linux/spinlock.h> > #include <linux/types.h> > #include <linux/atomic.h> > #include <linux/math64.h> > +#include <linux/crypto.h> > +#include <linux/string.h> > #include "tmem.h" > > #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; > } > > +/* 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 > * 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; > unsigned budnum = zbud_budnum(zh); > - size_t out_len = PAGE_SIZE; > + unsigned int out_len = PAGE_SIZE; > char *to_va, *from_va; > unsigned size; > 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); > size = zh->size; > from_va = zbud_data(zh, size); > - ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len); > - BUG_ON(ret != LZO_E_OK); > + ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, from_va, size, > + to_va, &out_len); > + BUG_ON(ret); > BUG_ON(out_len != PAGE_SIZE); > kunmap_atomic(to_va, KM_USER0); > out: > @@ -624,7 +659,7 @@ static int zbud_show_cumul_chunk_counts(char *buf) > > /********** > * 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. > * > * 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) > { > - size_t clen = PAGE_SIZE; > + unsigned int clen = PAGE_SIZE; > char *to_va; > unsigned size; > 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); > BUG_ON(size == 0); > to_va = kmap_atomic(page, KM_USER0); > - ret = lzo1x_decompress_safe((char *)zv + sizeof(*zv), > - size, to_va, &clen); > + ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, (char *)zv + sizeof(*zv), > + size, to_va, &clen); > kunmap_atomic(to_va, KM_USER0); > - BUG_ON(ret != LZO_E_OK); > + BUG_ON(ret); > BUG_ON(clen != PAGE_SIZE); > } > > @@ -1286,25 +1321,24 @@ static struct tmem_pamops zcache_pamops = { > * 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); > +#define ZCACHE_DSTMEM_ORDER 1 > > static int zcache_compress(struct page *from, void **out_va, size_t *out_len) > { > int ret = 0; > unsigned char *dmem = __get_cpu_var(zcache_dstmem); > - unsigned char *wmem = __get_cpu_var(zcache_workmem); > char *from_va; > > BUG_ON(!irqs_disabled()); > - if (unlikely(dmem == NULL || wmem == NULL)) > - goto out; /* no buffer, so can't compress */ > + if (unlikely(dmem == NULL)) > + 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); > mb(); > - ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem); > - BUG_ON(ret != LZO_E_OK); > + ret = zcache_comp_op(ZCACHE_COMPOP_COMPRESS, from_va, PAGE_SIZE, dmem, > + (unsigned int *)out_len); > + BUG_ON(ret); > *out_va = dmem; > kunmap_atomic(from_va, KM_USER0); > ret = 1; > @@ -1312,29 +1346,48 @@ out: > 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, > unsigned long action, void *pcpu) > { > - int cpu = (long)pcpu; > + int ret, cpu = (long)pcpu; > struct zcache_preload *kp; > > switch (action) { > 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( > - GFP_KERNEL | __GFP_REPEAT, > - LZO_DSTMEM_PAGE_ORDER), > - per_cpu(zcache_workmem, cpu) = > - kzalloc(LZO1X_MEM_COMPRESS, > - GFP_KERNEL | __GFP_REPEAT); > + GFP_KERNEL | __GFP_REPEAT, ZCACHE_DSTMEM_ORDER); > break; > case CPU_DEAD: > case CPU_UP_CANCELED: > + zcache_comp_cpu_down(cpu); > free_pages((unsigned long)per_cpu(zcache_dstmem, cpu), > - LZO_DSTMEM_PAGE_ORDER); > + ZCACHE_DSTMEM_ORDER); > per_cpu(zcache_dstmem, cpu) = NULL; > - kfree(per_cpu(zcache_workmem, cpu)); > - per_cpu(zcache_workmem, cpu) = NULL; > kp = &per_cpu(zcache_preloads, cpu); > while (kp->nr) { > kmem_cache_free(zcache_objnode_cache, > @@ -1919,6 +1972,44 @@ static int __init no_frontswap(char *s) > > __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) > { > int ret = 0; > @@ -1941,6 +2032,11 @@ static int __init zcache_init(void) > pr_err("zcache: can't register cpu notifier\n"); > goto out; > } > + ret = zcache_comp_init(); > + if (ret) { > + pr_err("zcache: compressor initialization failed\n"); > + goto out; > + } > for_each_online_cpu(cpu) { > void *pcpu = (void *)(long)cpu; > zcache_cpu_notifier(&zcache_cpu_notifier_block, _______________________________________________ devel mailing list devel@xxxxxxxxxxxxxxxxxxxxxx http://driverdev.linuxdriverproject.org/mailman/listinfo/devel