blob: d7a9b737e4288985e656d2f87ce840200ea8632b [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
#include "erofs/dedupe.h"
#include "liberofs_xxhash.h"
#include <stdlib.h>
struct z_erofs_dedupe_ext_item {
struct list_head list;
struct z_erofs_dedupe_ext_item *revoke;
struct z_erofs_inmem_extent e;
u64 xxh64;
};
static struct list_head dupl_ext[65536];
static struct z_erofs_dedupe_ext_item *revoke_list;
int z_erofs_dedupe_ext_insert(struct z_erofs_inmem_extent *e,
u64 hash)
{
struct z_erofs_dedupe_ext_item *item;
struct list_head *p;
item = malloc(sizeof(struct z_erofs_dedupe_ext_item));
if (!item)
return -ENOMEM;
item->e = *e;
item->xxh64 = hash;
p = &dupl_ext[hash & (ARRAY_SIZE(dupl_ext) - 1)];
list_add_tail(&item->list, p);
item->revoke = revoke_list;
revoke_list = item;
return 0;
}
erofs_off_t z_erofs_dedupe_ext_match(struct erofs_sb_info *sbi,
u8 *encoded, unsigned int len,
bool raw, u64 *hash)
{
struct z_erofs_dedupe_ext_item *item;
struct list_head *p;
u64 _xxh64;
char *memb = NULL;
int ret;
*hash = _xxh64 = xxh64(encoded, len, 0);
p = &dupl_ext[_xxh64 & (ARRAY_SIZE(dupl_ext) - 1)];
list_for_each_entry(item, p, list) {
if (item->xxh64 == _xxh64 && item->e.plen == len &&
item->e.raw == raw) {
if (!memb) {
memb = malloc(len);
if (!memb)
break;
}
ret = erofs_dev_read(sbi, 0, memb, item->e.pstart, len);
if (ret < 0 || memcmp(memb, encoded, len))
continue;
free(memb);
return item->e.pstart;
}
}
free(memb);
return 0;
}
void z_erofs_dedupe_ext_commit(bool drop)
{
if (drop) {
struct z_erofs_dedupe_ext_item *item, *n;
for (item = revoke_list; item; item = n) {
n = item->revoke;
list_del(&item->list);
free(item);
}
}
revoke_list = NULL;
}
int z_erofs_dedupe_ext_init(void)
{
struct list_head *p;
for (p = dupl_ext; p < dupl_ext + ARRAY_SIZE(dupl_ext); ++p)
init_list_head(p);
return 0;
}
void z_erofs_dedupe_ext_exit(void)
{
struct z_erofs_dedupe_ext_item *item, *n;
struct list_head *p;
if (!dupl_ext[0].next)
return;
z_erofs_dedupe_commit(true);
for (p = dupl_ext; p < dupl_ext + ARRAY_SIZE(dupl_ext); ++p) {
list_for_each_entry_safe(item, n, p, list) {
list_del(&item->list);
free(item);
}
}
}