forked from gerard/ext4fuse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dcache.c
128 lines (104 loc) · 3.91 KB
/
dcache.c
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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
* Copyright (c) 2010, Gerard Lledó Vives, [email protected]
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See README and COPYING for
* more details.
*/
#include <stdlib.h>
#include <string.h>
#include "types/e4f_dcache.h"
#include "logging.h"
#define DCACHE_ENTRY_CALLOC() calloc(1, sizeof(struct dcache_entry))
#define DCACHE_ENTRY_LIFE 8
/* Locking for the dcache is tricky. What we try to do is to keep insertions
* and lookups threadsafe by atomic updates. That keeps the tree safe, but
* means that eventually there might be duplicated entries.
* However, when entry pruning is implemented, there might be a need to take
* real locks into use.
*
* About string handling in this file, it should be said that all strings are
* provided with a length. The idea is that usually strings are passed here as
* they appear on the fuse call (with arbitrary directory depth) but we are
* just interested on one path token. Such calculation is done somewhere else,
* so we just take it from whoever calls us.
* All this hassle is basically to avoid copying around strings. */
static struct dcache_entry root;
int dcache_init_root(uint32_t n)
{
if (root.inode) {
WARNING("Reinitializing dcache not allowed. Skipped.");
return -1;
}
/* Root entry doesn't need most of the fields. Namely, it only uses the
* inode field and the childs pointer. */
INFO("Initializing root dcache entry");
root.inode = n;
root.childs = NULL;
return 0;
}
/* Inserts a node as a childs of a given parent. The parent is updated to
* point the newly inserted childs as the first childs. We return the new
* entry so that further entries can be inserted.
*
* [0] [0]
* / ==> \
* / ==> \
* .->[1]->[2]-. .->[1]->[3]->[2]-.
* `-----------´ `----------------´
*/
struct dcache_entry *dcache_insert(struct dcache_entry *parent, const char *name, int namelen, uint32_t n)
{
DEBUG("Inserting %s,%d to dcache", name, namelen);
/* TODO: Deal with names that exceed the allocated size */
if (namelen + 1 > DCACHE_ENTRY_NAME_LEN) return NULL;
if (parent == NULL) {
parent = &root;
ASSERT(parent->inode);
}
struct dcache_entry *new_entry = DCACHE_ENTRY_CALLOC();
strncpy(new_entry->name, name, namelen);
new_entry->name[namelen] = 0;
new_entry->inode = n;
if (!parent->childs) {
new_entry->siblings = new_entry;
parent->childs = new_entry;
} else {
new_entry->siblings = parent->childs->siblings;
parent->childs->siblings = new_entry;
parent->childs = new_entry;
}
return new_entry;
}
/* Lookup a cache entry for a given file name. Return value is a struct pointer
* that can be used to both obtain the inode number and insert further child
* entries. */
/* TODO: Prune entries by using the LRU counter */
struct dcache_entry *dcache_lookup(struct dcache_entry *parent, const char *name, int namelen)
{
if (parent == NULL) {
parent = &root;
}
if (!parent->childs) {
DEBUG("Looking up %s,%d: Not found (no childs)", name, namelen);
return NULL;
}
/* Iterate the list of siblings to see if there is any match */
struct dcache_entry *iter = parent->childs;
do {
if (strncmp(iter->name, name, namelen) == 0 && iter->name[namelen] == 0) {
parent->childs = iter;
DEBUG("Looking up %s,%d: Found", name, namelen);
return iter;
}
iter = iter->siblings;
} while (iter != parent->childs);
DEBUG("Looking up %s,%d: Not found", name, namelen);
return NULL;
}
uint32_t dcache_get_inode(struct dcache_entry *entry)
{
if (entry) return entry->inode;
else return root.inode;
}