cbd/include/linux/dm-compress.h

357 lines
7.9 KiB
C

#ifndef _LINUX_DM_COMPRESS_H
#define _LINUX_DM_COMPRESS_H
#ifndef SECTOR_SHIFT
#define SECTOR_SHIFT 9
#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, u32 idx, struct lblk_alloc_elem* elem)
{
const u8* raw = buf + idx * lblk_alloc_elem_len(params);
u32 n;
if (params->lblk_shift + PBLK_SHIFT > 16) {
elem->len = get32_le(&raw);
}
else {
elem->len = get16_le(&raw);
}
if (params->nr_pblk <= 0xffff) {
for (n = 0; n < lblk_per_pblk(params); ++n) {
elem->pblk[n] = get16_le(&raw);
}
}
else if (params->nr_pblk <= 0xffffffff) {
for (n = 0; n < lblk_per_pblk(params); ++n) {
elem->pblk[n] = get32_le(&raw);
}
}
else {
for (n = 0; n < lblk_per_pblk(params); ++n) {
elem->pblk[n] = get48_le(&raw);
}
}
}
static inline void
lblk_alloc_elem_put(const struct cbd_params* params,
void* buf, u32 idx, const struct lblk_alloc_elem* elem)
{
u8* raw = buf + idx * lblk_alloc_elem_len(params);
u32 n;
if (params->lblk_shift + PBLK_SHIFT > 16) {
put32_le(&raw, elem->len);
}
else {
put16_le(&raw, elem->len);
}
if (params->nr_pblk <= 0xffff) {
for (n = 0; n < lblk_per_pblk(params); ++n) {
put16_le(&raw, elem->pblk[n]);
}
}
else if (params->nr_pblk <= 0xffffffff) {
for (n = 0; n < lblk_per_pblk(params); ++n) {
put32_le(&raw, elem->pblk[n]);
}
}
else {
for (n = 0; n < lblk_per_pblk(params); ++n) {
put48_le(&raw, elem->pblk[n]);
}
}
}
#endif /* _LINUX_DM_COMPRESS_H */