File: dedupe_ext.c

package info (click to toggle)
erofs-utils 1.8.10-1
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 1,128 kB
  • sloc: ansic: 20,839; makefile: 164; sh: 33
file content (103 lines) | stat: -rw-r--r-- 2,230 bytes parent folder | download
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);
		}
	}
}