358 lines
7.8 KiB
C
358 lines
7.8 KiB
C
#ifndef _LINUX_DM_COMPRESS_H
|
|
#define _LINUX_DM_COMPRESS_H
|
|
|
|
#ifndef SECTOR_SHIFT
|
|
#define SECTOR_SHIFT 9
|
|
#endif
|
|
#ifndef SECTOR_SIZE
|
|
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
|
|
#endif
|
|
|
|
#define PBLK_SHIFT 12
|
|
#define PBLK_SIZE (1 << PBLK_SHIFT)
|
|
#define PBLK_SIZE_BITS (PBLK_SIZE * BITS_PER_BYTE)
|
|
#define PBLK_PER_SECTOR (1 << (PBLK_SHIFT - SECTOR_SHIFT))
|
|
|
|
#define LBLK_SHIFT_MIN 1
|
|
#define LBLK_SHIFT_MAX (20 - PBLK_SHIFT)
|
|
|
|
#define CBD_HEADER_BLOCKS 1
|
|
|
|
#define CBD_UNCOMPRESSED 1
|
|
|
|
static const u8 CBD_MAGIC[] = { 'C', 'B', 'D', '\0' };
|
|
static const u16 CBD_VERSION_MAJOR = 1;
|
|
static const u16 CBD_VERSION_MINOR = 1;
|
|
|
|
enum cbd_alg {
|
|
CBD_ALG_NONE,
|
|
CBD_ALG_LZ4,
|
|
CBD_ALG_ZLIB,
|
|
/* lzo, zstd, ... */
|
|
CBD_ALG_MAX
|
|
};
|
|
|
|
struct cbd_params {
|
|
u8 algorithm; /* cbd_alg */
|
|
u8 compression; /* 0..9 */
|
|
u16 lblk_shift;
|
|
u64 nr_pblk;
|
|
u32 nr_zones;
|
|
u32 lblk_per_zone;
|
|
};
|
|
|
|
struct cbd_header {
|
|
u8 magic[4];
|
|
u16 version_major;
|
|
u16 version_minor;
|
|
struct cbd_params params;
|
|
};
|
|
|
|
struct lblk_alloc_elem
|
|
{
|
|
u32 len; /* Compressed length */
|
|
u64 pblk[1]; /* Vector of physical blocks */
|
|
};
|
|
|
|
static inline void
|
|
get_mem(const u8** raw, u8* buf, size_t len)
|
|
{
|
|
memcpy(buf, *raw, len);
|
|
*raw += len;
|
|
}
|
|
|
|
static inline void
|
|
put_mem(u8** raw, const u8* buf, size_t len)
|
|
{
|
|
memcpy(*raw, buf, len);
|
|
*raw += len;
|
|
}
|
|
|
|
static inline u8
|
|
get_byte(const u8** raw)
|
|
{
|
|
u8 val = **raw;
|
|
*raw += sizeof(u8);
|
|
return val;
|
|
}
|
|
|
|
static inline void
|
|
put_byte(u8** raw, u8 val)
|
|
{
|
|
**raw = val;
|
|
*raw += sizeof(u8);
|
|
}
|
|
|
|
static inline u16
|
|
get16_le(const u8** raw)
|
|
{
|
|
u16 leval = 0;
|
|
memcpy(&leval, *raw, sizeof(leval));
|
|
*raw += sizeof(leval);
|
|
return __le16_to_cpu(leval);
|
|
}
|
|
|
|
static inline void
|
|
put16_le(u8** raw, u16 val)
|
|
{
|
|
u16 leval = __cpu_to_le16(val);
|
|
memcpy(*raw, &leval, sizeof(leval));
|
|
*raw += sizeof(leval);
|
|
}
|
|
|
|
static inline u32
|
|
get32_le(const u8** raw)
|
|
{
|
|
u32 leval = 0;
|
|
memcpy(&leval, *raw, sizeof(leval));
|
|
*raw += sizeof(leval);
|
|
return __le32_to_cpu(leval);
|
|
}
|
|
|
|
static inline void
|
|
put32_le(u8** raw, u32 val)
|
|
{
|
|
u32 leval = __cpu_to_le32(val);
|
|
memcpy(*raw, &leval, sizeof(leval));
|
|
*raw += sizeof(leval);
|
|
}
|
|
|
|
static inline u64
|
|
get48_le(const u8** raw)
|
|
{
|
|
u64 leval = 0;
|
|
memcpy(&leval, *raw, 6);
|
|
*raw += 6;
|
|
return __le64_to_cpu(leval);
|
|
}
|
|
|
|
static inline void
|
|
put48_le(u8** raw, u64 val)
|
|
{
|
|
u64 leval = __cpu_to_le64(val);
|
|
memcpy(*raw, &leval, 6);
|
|
*raw += 6;
|
|
}
|
|
|
|
static inline u64
|
|
get64_le(const u8** raw)
|
|
{
|
|
u64 leval = 0;
|
|
memcpy(&leval, *raw, sizeof(leval));
|
|
*raw += sizeof(leval);
|
|
return __le64_to_cpu(leval);
|
|
}
|
|
|
|
static inline void
|
|
put64_le(u8** raw, u64 val)
|
|
{
|
|
u64 leval = __cpu_to_le64(val);
|
|
memcpy(*raw, &leval, sizeof(leval));
|
|
*raw += sizeof(leval);
|
|
}
|
|
|
|
|
|
|
|
static inline u32
|
|
lblk_per_pblk(const struct cbd_params* params)
|
|
{
|
|
return (1 << params->lblk_shift);
|
|
}
|
|
|
|
static inline u32
|
|
pblk_alloc_len(const struct cbd_params* params)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static inline u32
|
|
lblk_alloc_elem_len(const struct cbd_params* params)
|
|
{
|
|
u32 elem_len_bytes = (params->lblk_shift + PBLK_SHIFT > 16) ? 4 : 2;
|
|
u32 elem_pblk_bytes = (params->nr_pblk <= 0xffff ? 2 :
|
|
(params->nr_pblk <= 0xffffffff ? 4 : 6));
|
|
return elem_len_bytes + (1 << params->lblk_shift) * elem_pblk_bytes;
|
|
}
|
|
|
|
static inline u32
|
|
lblk_alloc_len(const struct cbd_params* params)
|
|
{
|
|
return DIV_ROUND_UP(params->lblk_per_zone * lblk_alloc_elem_len(params), PBLK_SIZE);
|
|
}
|
|
|
|
static inline u32
|
|
zone_metadata_len(const struct cbd_params* params)
|
|
{
|
|
return pblk_alloc_len(params) +
|
|
lblk_alloc_len(params);
|
|
}
|
|
|
|
static inline u32
|
|
zone_data_len(const struct cbd_params* params)
|
|
{
|
|
return pblk_alloc_len(params) * PBLK_SIZE * BITS_PER_BYTE;
|
|
}
|
|
|
|
static inline u32
|
|
zone_len(const struct cbd_params* params)
|
|
{
|
|
return zone_metadata_len(params) +
|
|
zone_data_len(params);
|
|
}
|
|
|
|
static inline u64
|
|
zone_off(const struct cbd_params* params, u32 idx)
|
|
{
|
|
return CBD_HEADER_BLOCKS + idx * zone_len(params);
|
|
}
|
|
|
|
static inline u64
|
|
pblk_alloc_off(const struct cbd_params* params, u32 idx)
|
|
{
|
|
return zone_off(params, idx) + 0;
|
|
}
|
|
|
|
static inline u64
|
|
lblk_alloc_off(const struct cbd_params* params, u32 idx)
|
|
{
|
|
return zone_off(params, idx) +
|
|
pblk_alloc_len(params);
|
|
}
|
|
|
|
static inline u64
|
|
zone_data_off(const struct cbd_params* params, u32 idx)
|
|
{
|
|
return zone_off(params, idx) +
|
|
pblk_alloc_len(params) +
|
|
lblk_alloc_len(params);
|
|
}
|
|
|
|
static inline void
|
|
cbd_header_get(const u8* buf, struct cbd_header* header)
|
|
{
|
|
get_mem(&buf, header->magic, sizeof(header->magic));
|
|
header->version_major = get16_le(&buf);
|
|
header->version_minor = get16_le(&buf);
|
|
header->params.algorithm = get_byte(&buf);
|
|
header->params.compression = get_byte(&buf);
|
|
header->params.lblk_shift = get16_le(&buf);
|
|
header->params.nr_pblk = get64_le(&buf);
|
|
header->params.nr_zones = get32_le(&buf);
|
|
header->params.lblk_per_zone = get32_le(&buf);
|
|
}
|
|
|
|
static inline void
|
|
cbd_header_put(u8* buf, const struct cbd_header* header)
|
|
{
|
|
put_mem(&buf, header->magic, sizeof(header->magic));
|
|
put16_le(&buf, header->version_major);
|
|
put16_le(&buf, header->version_minor);
|
|
put_byte(&buf, header->params.algorithm);
|
|
put_byte(&buf, header->params.compression);
|
|
put16_le(&buf, header->params.lblk_shift);
|
|
put64_le(&buf, header->params.nr_pblk);
|
|
put32_le(&buf, header->params.nr_zones);
|
|
put32_le(&buf, header->params.lblk_per_zone);
|
|
}
|
|
|
|
/*
|
|
* XXX:
|
|
* nr_bits = pblk_alloc_len(params) * PBLK_SIZE;
|
|
* bit = find_next_zero_bit_le(buf, nr_bits);
|
|
* if (bit < nr_bits) {
|
|
* set_bit_le(bit, buf);
|
|
* }
|
|
* return bit;
|
|
*/
|
|
static inline u32
|
|
cbd_bitmap_alloc(u8* buf, u32 bitsize)
|
|
{
|
|
u32 off = 0;
|
|
u32 bit = 0;
|
|
|
|
for (off = 0; off < bitsize / BITS_PER_BYTE; ++off) {
|
|
if (buf[off] != 0xff) {
|
|
while (buf[off] & (1 << bit)) {
|
|
++bit;
|
|
}
|
|
buf[off] |= (1 << bit);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return off * BITS_PER_BYTE + bit;
|
|
}
|
|
|
|
/*
|
|
* XXX:
|
|
* clear_bit_le(bit, buf);
|
|
*/
|
|
static inline void
|
|
cbd_bitmap_free(u8* buf, u32 idx)
|
|
{
|
|
u32 off = idx / BITS_PER_BYTE;
|
|
u32 bit = idx % BITS_PER_BYTE;
|
|
|
|
buf[off] &= ~(1 << bit);
|
|
}
|
|
|
|
static inline void
|
|
lblk_alloc_elem_get(const struct cbd_params* params,
|
|
const u8* buf, struct lblk_alloc_elem* elem)
|
|
{
|
|
u32 n;
|
|
|
|
if (params->lblk_shift + PBLK_SHIFT > 16) {
|
|
elem->len = get32_le(&buf);
|
|
}
|
|
else {
|
|
elem->len = get16_le(&buf);
|
|
}
|
|
if (params->nr_pblk <= 0xffff) {
|
|
for (n = 0; n < lblk_per_pblk(params); ++n) {
|
|
elem->pblk[n] = get16_le(&buf);
|
|
}
|
|
}
|
|
else if (params->nr_pblk <= 0xffffffff) {
|
|
for (n = 0; n < lblk_per_pblk(params); ++n) {
|
|
elem->pblk[n] = get32_le(&buf);
|
|
}
|
|
}
|
|
else {
|
|
for (n = 0; n < lblk_per_pblk(params); ++n) {
|
|
elem->pblk[n] = get48_le(&buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
lblk_alloc_elem_put(const struct cbd_params* params,
|
|
u8* buf, const struct lblk_alloc_elem* elem)
|
|
{
|
|
u32 n;
|
|
|
|
if (params->lblk_shift + PBLK_SHIFT > 16) {
|
|
put32_le(&buf, elem->len);
|
|
}
|
|
else {
|
|
put16_le(&buf, elem->len);
|
|
}
|
|
if (params->nr_pblk <= 0xffff) {
|
|
for (n = 0; n < lblk_per_pblk(params); ++n) {
|
|
put16_le(&buf, elem->pblk[n]);
|
|
}
|
|
}
|
|
else if (params->nr_pblk <= 0xffffffff) {
|
|
for (n = 0; n < lblk_per_pblk(params); ++n) {
|
|
put32_le(&buf, elem->pblk[n]);
|
|
}
|
|
}
|
|
else {
|
|
for (n = 0; n < lblk_per_pblk(params); ++n) {
|
|
put48_le(&buf, elem->pblk[n]);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif /* _LINUX_DM_COMPRESS_H */
|