Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
fs
btrfs
ulist.c
Go to the documentation of this file.
1
/*
2
* Copyright (C) 2011 STRATO AG
3
* written by Arne Jansen <
[email protected]
>
4
* Distributed under the GNU GPL license version 2.
5
*/
6
7
#include <linux/slab.h>
8
#include <linux/module.h>
9
#include "
ulist.h
"
10
11
/*
12
* ulist is a generic data structure to hold a collection of unique u64
13
* values. The only operations it supports is adding to the list and
14
* enumerating it.
15
* It is possible to store an auxiliary value along with the key.
16
*
17
* The implementation is preliminary and can probably be sped up
18
* significantly. A first step would be to store the values in an rbtree
19
* as soon as ULIST_SIZE is exceeded.
20
*
21
* A sample usage for ulists is the enumeration of directed graphs without
22
* visiting a node twice. The pseudo-code could look like this:
23
*
24
* ulist = ulist_alloc();
25
* ulist_add(ulist, root);
26
* ULIST_ITER_INIT(&uiter);
27
*
28
* while ((elem = ulist_next(ulist, &uiter)) {
29
* for (all child nodes n in elem)
30
* ulist_add(ulist, n);
31
* do something useful with the node;
32
* }
33
* ulist_free(ulist);
34
*
35
* This assumes the graph nodes are adressable by u64. This stems from the
36
* usage for tree enumeration in btrfs, where the logical addresses are
37
* 64 bit.
38
*
39
* It is also useful for tree enumeration which could be done elegantly
40
* recursively, but is not possible due to kernel stack limitations. The
41
* loop would be similar to the above.
42
*/
43
51
void
ulist_init
(
struct
ulist
*
ulist
)
52
{
53
ulist->
nnodes
= 0;
54
ulist->
nodes
= ulist->
int_nodes
;
55
ulist->
nodes_alloced
=
ULIST_SIZE
;
56
}
57
EXPORT_SYMBOL
(
ulist_init
);
58
66
void
ulist_fini
(
struct
ulist
*
ulist
)
67
{
68
/*
69
* The first ULIST_SIZE elements are stored inline in struct ulist.
70
* Only if more elements are alocated they need to be freed.
71
*/
72
if
(ulist->
nodes_alloced
>
ULIST_SIZE
)
73
kfree
(ulist->
nodes
);
74
ulist->
nodes_alloced
= 0;
/* in case ulist_fini is called twice */
75
}
76
EXPORT_SYMBOL
(
ulist_fini
);
77
85
void
ulist_reinit
(
struct
ulist
*
ulist
)
86
{
87
ulist_fini
(ulist);
88
ulist_init
(ulist);
89
}
90
EXPORT_SYMBOL
(
ulist_reinit
);
91
98
struct
ulist
*
ulist_alloc
(
gfp_t
gfp_mask
)
99
{
100
struct
ulist
*
ulist
=
kmalloc
(
sizeof
(*ulist), gfp_mask);
101
102
if
(!ulist)
103
return
NULL
;
104
105
ulist_init
(ulist);
106
107
return
ulist;
108
}
109
EXPORT_SYMBOL
(
ulist_alloc
);
110
117
void
ulist_free
(
struct
ulist
*
ulist
)
118
{
119
if
(!ulist)
120
return
;
121
ulist_fini
(ulist);
122
kfree
(ulist);
123
}
124
EXPORT_SYMBOL
(
ulist_free
);
125
146
int
ulist_add
(
struct
ulist
*
ulist
,
u64
val
,
u64
aux
,
gfp_t
gfp_mask
)
147
{
148
return
ulist_add_merge
(ulist, val, aux,
NULL
, gfp_mask);
149
}
150
151
int
ulist_add_merge
(
struct
ulist
*
ulist
,
u64
val
,
u64
aux
,
152
u64
*old_aux,
gfp_t
gfp_mask
)
153
{
154
int
i
;
155
156
for
(i = 0; i < ulist->
nnodes
; ++
i
) {
157
if
(ulist->
nodes
[i].val == val) {
158
if
(old_aux)
159
*old_aux = ulist->
nodes
[
i
].aux;
160
return
0;
161
}
162
}
163
164
if
(ulist->
nnodes
>= ulist->
nodes_alloced
) {
165
u64
new_alloced = ulist->
nodes_alloced
+ 128;
166
struct
ulist_node
*new_nodes;
167
void
*old =
NULL
;
168
169
/*
170
* if nodes_alloced == ULIST_SIZE no memory has been allocated
171
* yet, so pass NULL to krealloc
172
*/
173
if
(ulist->
nodes_alloced
>
ULIST_SIZE
)
174
old = ulist->
nodes
;
175
176
new_nodes =
krealloc
(old,
sizeof
(*new_nodes) * new_alloced,
177
gfp_mask);
178
if
(!new_nodes)
179
return
-
ENOMEM
;
180
181
if
(!old)
182
memcpy
(new_nodes, ulist->
int_nodes
,
183
sizeof
(ulist->
int_nodes
));
184
185
ulist->
nodes
= new_nodes;
186
ulist->
nodes_alloced
= new_alloced;
187
}
188
ulist->
nodes
[ulist->
nnodes
].val =
val
;
189
ulist->
nodes
[ulist->
nnodes
].aux =
aux
;
190
++ulist->
nnodes
;
191
192
return
1;
193
}
194
EXPORT_SYMBOL
(
ulist_add
);
195
212
struct
ulist_node
*
ulist_next
(
struct
ulist
*
ulist
,
struct
ulist_iterator
*uiter)
213
{
214
if
(ulist->
nnodes
== 0)
215
return
NULL
;
216
if
(uiter->
i
< 0 || uiter->
i
>= ulist->
nnodes
)
217
return
NULL
;
218
219
return
&ulist->
nodes
[uiter->
i
++];
220
}
221
EXPORT_SYMBOL
(
ulist_next
);
Generated on Thu Jan 10 2013 14:45:48 for Linux Kernel by
1.8.2