1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
|
// 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);
}
}
}
|