blob: 620768d7de2025691a448f7b8db34e7c19304e1f [file] [log] [blame]
/**
* compress.c
*
* Copyright (c) 2020 Google Inc.
* Robin Hsu <robinhsu@google.com>
* : add sload compression support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* for config.h for general environment (non-Android) */
#include "f2fs.h"
#include "compress.h"
#ifdef HAVE_LIBLZO2
#include <lzo/lzo1x.h> /* for lzo1x_1_15_compress() */
#endif
#ifdef HAVE_LIBLZ4
#include <lz4.h> /* for LZ4_compress_fast_extState() */
#endif
/*
* macro/constants borrowed from kernel header (GPL-2.0):
* include/linux/lzo.h, and include/linux/lz4.h
*/
#ifdef HAVE_LIBLZO2
#define lzo1x_worst_compress(x) ((x) + (x) / 16 + 64 + 3 + 2)
#define LZO_WORK_SIZE ALIGN_UP(LZO1X_1_15_MEM_COMPRESS, 8)
#endif
#ifdef HAVE_LIBLZ4
#define LZ4_MEMORY_USAGE 14
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
#ifndef LZ4_STREAMSIZE
#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long))
#endif
#define LZ4_MEM_COMPRESS LZ4_STREAMSIZE
#define LZ4_ACCELERATION_DEFAULT 1
#define LZ4_WORK_SIZE ALIGN_UP(LZ4_MEM_COMPRESS, 8)
#endif
#if defined(HAVE_LIBLZO2) || defined(HAVE_LIBLZ4)
static void reset_cc(struct compress_ctx *cc)
{
memset(cc->rbuf, 0, cc->cluster_size * F2FS_BLKSIZE);
memset(cc->cbuf->cdata, 0, cc->cluster_size * F2FS_BLKSIZE
- F2FS_BLKSIZE);
}
#endif
#ifdef HAVE_LIBLZO2
static void lzo_compress_init(struct compress_ctx *cc)
{
size_t size = cc->cluster_size * F2FS_BLKSIZE;
size_t alloc = size + lzo1x_worst_compress(size)
+ COMPRESS_HEADER_SIZE + LZO_WORK_SIZE;
cc->private = malloc(alloc);
ASSERT(cc->private);
cc->rbuf = (char *) cc->private + LZO_WORK_SIZE;
cc->cbuf = (struct compress_data *)((char *) cc->rbuf + size);
}
static int lzo_compress(struct compress_ctx *cc)
{
int ret = lzo1x_1_15_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata,
(lzo_uintp)(&cc->clen), cc->private);
cc->cbuf->clen = cpu_to_le32(cc->clen);
return ret;
}
#endif
#ifdef HAVE_LIBLZ4
static void lz4_compress_init(struct compress_ctx *cc)
{
size_t size = cc->cluster_size * F2FS_BLKSIZE;
size_t alloc = size + LZ4_COMPRESSBOUND(size)
+ COMPRESS_HEADER_SIZE + LZ4_WORK_SIZE;
cc->private = malloc(alloc);
ASSERT(cc->private);
cc->rbuf = (char *) cc->private + LZ4_WORK_SIZE;
cc->cbuf = (struct compress_data *)((char *) cc->rbuf + size);
}
static int lz4_compress(struct compress_ctx *cc)
{
cc->clen = LZ4_compress_fast_extState(cc->private, cc->rbuf,
(char *)cc->cbuf->cdata, cc->rlen,
cc->rlen - F2FS_BLKSIZE * c.compress.min_blocks,
LZ4_ACCELERATION_DEFAULT);
if (!cc->clen)
return 1;
cc->cbuf->clen = cpu_to_le32(cc->clen);
return 0;
}
#endif
const char *supported_comp_names[] = {
"lzo",
"lz4",
"",
};
compress_ops supported_comp_ops[] = {
#ifdef HAVE_LIBLZO2
{lzo_compress_init, lzo_compress, reset_cc},
#else
{NULL, NULL, NULL},
#endif
#ifdef HAVE_LIBLZ4
{lz4_compress_init, lz4_compress, reset_cc},
#else
{NULL, NULL, NULL},
#endif
};
/* linked list */
typedef struct _ext_t {
const char *ext;
struct _ext_t *next;
} ext_t;
static ext_t *extension_list;
static bool ext_found(const char *ext)
{
ext_t *p = extension_list;
while (p != NULL && strcmp(ext, p->ext))
p = p->next;
return (p != NULL);
}
static const char *get_ext(const char *path)
{
char *p = strrchr(path, '.');
return p == NULL ? path + strlen(path) : p + 1;
}
static bool ext_do_filter(const char *path)
{
return (ext_found(get_ext(path)) == true) ^
(c.compress.filter == COMPR_FILTER_ALLOW);
}
static void ext_filter_add(const char *ext)
{
ext_t *node;
ASSERT(ext != NULL);
if (ext_found(ext))
return; /* ext was already registered */
node = malloc(sizeof(ext_t));
ASSERT(node != NULL);
node->ext = ext;
node->next = extension_list;
extension_list = node;
}
static void ext_filter_destroy(void)
{
ext_t *p;
while (extension_list != NULL) {
p = extension_list;
extension_list = p->next;
free(p);
}
}
filter_ops ext_filter = {
.add = ext_filter_add,
.destroy = ext_filter_destroy,
.filter = ext_do_filter,
};