|
Lines 8-13
Link Here
|
| 8 |
#include <linux/export.h> |
8 |
#include <linux/export.h> |
| 9 |
#include "ulist.h" |
9 |
#include "ulist.h" |
| 10 |
|
10 |
|
|
|
11 |
static struct kmem_cache *ulist_node_cachep; |
| 12 |
|
| 11 |
/* |
13 |
/* |
| 12 |
* ulist is a generic data structure to hold a collection of unique u64 |
14 |
* 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 |
15 |
* values. The only operations it supports is adding to the list and |
|
Lines 51-62
Link Here
|
| 51 |
void ulist_init(struct ulist *ulist) |
53 |
void ulist_init(struct ulist *ulist) |
| 52 |
{ |
54 |
{ |
| 53 |
ulist->nnodes = 0; |
55 |
ulist->nnodes = 0; |
| 54 |
ulist->nodes = ulist->int_nodes; |
56 |
ulist->last_node = NULL; |
| 55 |
ulist->nodes_alloced = ULIST_SIZE; |
|
|
| 56 |
ulist->root = RB_ROOT; |
57 |
ulist->root = RB_ROOT; |
| 57 |
} |
58 |
} |
| 58 |
EXPORT_SYMBOL(ulist_init); |
59 |
EXPORT_SYMBOL(ulist_init); |
| 59 |
|
60 |
|
|
|
61 |
static void free_nodes(struct ulist *ulist) |
| 62 |
{ |
| 63 |
struct rb_node *n; |
| 64 |
struct ulist_node *un; |
| 65 |
|
| 66 |
n = rb_first(&ulist->root); |
| 67 |
while (n) { |
| 68 |
un = rb_entry(n, struct ulist_node, rb_node); |
| 69 |
n = rb_next(n); |
| 70 |
rb_erase(&un->rb_node, &ulist->root); |
| 71 |
un->next = NULL; |
| 72 |
if (!un->alloced) |
| 73 |
continue; |
| 74 |
kmem_cache_free(ulist_node_cachep, un); |
| 75 |
} |
| 76 |
} |
| 77 |
|
| 60 |
/** |
78 |
/** |
| 61 |
* ulist_fini - free up additionally allocated memory for the ulist |
79 |
* ulist_fini - free up additionally allocated memory for the ulist |
| 62 |
* @ulist: the ulist from which to free the additional memory |
80 |
* @ulist: the ulist from which to free the additional memory |
|
Lines 70-78
void ulist_fini(struct ulist *ulist)
Link Here
|
| 70 |
* The first ULIST_SIZE elements are stored inline in struct ulist. |
88 |
* The first ULIST_SIZE elements are stored inline in struct ulist. |
| 71 |
* Only if more elements are alocated they need to be freed. |
89 |
* Only if more elements are alocated they need to be freed. |
| 72 |
*/ |
90 |
*/ |
| 73 |
if (ulist->nodes_alloced > ULIST_SIZE) |
91 |
if (ulist->nnodes > ULIST_SIZE) |
| 74 |
kfree(ulist->nodes); |
92 |
free_nodes(ulist); |
| 75 |
ulist->nodes_alloced = 0; /* in case ulist_fini is called twice */ |
93 |
ulist->nnodes = 0; /* in case ulist_fini is called twice */ |
|
|
94 |
ulist->last_node = NULL; |
| 76 |
ulist->root = RB_ROOT; |
95 |
ulist->root = RB_ROOT; |
| 77 |
} |
96 |
} |
| 78 |
EXPORT_SYMBOL(ulist_fini); |
97 |
EXPORT_SYMBOL(ulist_fini); |
|
Lines 201-249
int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux,
Link Here
|
| 201 |
return 0; |
220 |
return 0; |
| 202 |
} |
221 |
} |
| 203 |
|
222 |
|
| 204 |
if (ulist->nnodes >= ulist->nodes_alloced) { |
223 |
if (ulist->nnodes >= ULIST_SIZE) { |
| 205 |
u64 new_alloced = ulist->nodes_alloced + 128; |
224 |
node = kmem_cache_alloc(ulist_node_cachep, gfp_mask); |
| 206 |
struct ulist_node *new_nodes; |
225 |
if (!node) |
| 207 |
void *old = NULL; |
|
|
| 208 |
int i; |
| 209 |
|
| 210 |
for (i = 0; i < ulist->nnodes; i++) |
| 211 |
rb_erase(&ulist->nodes[i].rb_node, &ulist->root); |
| 212 |
|
| 213 |
/* |
| 214 |
* if nodes_alloced == ULIST_SIZE no memory has been allocated |
| 215 |
* yet, so pass NULL to krealloc |
| 216 |
*/ |
| 217 |
if (ulist->nodes_alloced > ULIST_SIZE) |
| 218 |
old = ulist->nodes; |
| 219 |
|
| 220 |
new_nodes = krealloc(old, sizeof(*new_nodes) * new_alloced, |
| 221 |
gfp_mask); |
| 222 |
if (!new_nodes) |
| 223 |
return -ENOMEM; |
226 |
return -ENOMEM; |
| 224 |
|
227 |
node->val = val; |
| 225 |
if (!old) |
228 |
node->aux = aux; |
| 226 |
memcpy(new_nodes, ulist->int_nodes, |
229 |
node->alloced = 1; |
| 227 |
sizeof(ulist->int_nodes)); |
230 |
node->next = NULL; |
| 228 |
|
231 |
ret = ulist_rbtree_insert(ulist, node); |
| 229 |
ulist->nodes = new_nodes; |
232 |
if (ret) { |
| 230 |
ulist->nodes_alloced = new_alloced; |
233 |
kmem_cache_free(ulist_node_cachep, node); |
| 231 |
|
234 |
return ret; |
| 232 |
/* |
|
|
| 233 |
* krealloc actually uses memcpy, which does not copy rb_node |
| 234 |
* pointers, so we have to do it ourselves. Otherwise we may |
| 235 |
* be bitten by crashes. |
| 236 |
*/ |
| 237 |
for (i = 0; i < ulist->nnodes; i++) { |
| 238 |
ret = ulist_rbtree_insert(ulist, &ulist->nodes[i]); |
| 239 |
if (ret < 0) |
| 240 |
return ret; |
| 241 |
} |
235 |
} |
|
|
236 |
ulist->last_node->next = node; |
| 237 |
ulist->last_node = node; |
| 238 |
} else { |
| 239 |
ulist->int_nodes[ulist->nnodes].val = val; |
| 240 |
ulist->int_nodes[ulist->nnodes].aux = aux; |
| 241 |
ulist->int_nodes[ulist->nnodes].alloced = 0; |
| 242 |
ulist->int_nodes[ulist->nnodes].next = NULL; |
| 243 |
ret = ulist_rbtree_insert(ulist, |
| 244 |
&ulist->int_nodes[ulist->nnodes]); |
| 245 |
if (ret) |
| 246 |
return ret; |
| 247 |
node = &ulist->int_nodes[ulist->nnodes]; |
| 242 |
} |
248 |
} |
| 243 |
ulist->nodes[ulist->nnodes].val = val; |
249 |
if (ulist->last_node) |
| 244 |
ulist->nodes[ulist->nnodes].aux = aux; |
250 |
ulist->last_node->next = node; |
| 245 |
ret = ulist_rbtree_insert(ulist, &ulist->nodes[ulist->nnodes]); |
251 |
ulist->last_node = node; |
| 246 |
BUG_ON(ret); |
|
|
| 247 |
++ulist->nnodes; |
252 |
++ulist->nnodes; |
| 248 |
|
253 |
|
| 249 |
return 1; |
254 |
return 1; |
|
Lines 268-278
EXPORT_SYMBOL(ulist_add);
Link Here
|
| 268 |
*/ |
273 |
*/ |
| 269 |
struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_iterator *uiter) |
274 |
struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_iterator *uiter) |
| 270 |
{ |
275 |
{ |
| 271 |
if (ulist->nnodes == 0) |
276 |
if (ulist->last_node == NULL) |
| 272 |
return NULL; |
|
|
| 273 |
if (uiter->i < 0 || uiter->i >= ulist->nnodes) |
| 274 |
return NULL; |
277 |
return NULL; |
| 275 |
|
278 |
if (!uiter->cur) |
| 276 |
return &ulist->nodes[uiter->i++]; |
279 |
uiter->cur = &ulist->int_nodes[0]; |
|
|
280 |
else |
| 281 |
uiter->cur = uiter->cur->next; |
| 282 |
return uiter->cur; |
| 277 |
} |
283 |
} |
| 278 |
EXPORT_SYMBOL(ulist_next); |
284 |
EXPORT_SYMBOL(ulist_next); |
|
|
285 |
|
| 286 |
void ulist_destroy_cachep(void) |
| 287 |
{ |
| 288 |
if (ulist_node_cachep) |
| 289 |
kmem_cache_destroy(ulist_node_cachep); |
| 290 |
} |
| 291 |
|
| 292 |
int ulist_init_cachep(void) |
| 293 |
{ |
| 294 |
ulist_node_cachep = kmem_cache_create("ulist_node", |
| 295 |
sizeof(struct ulist_node), 0, |
| 296 |
SLAB_RECLAIM_ACCOUNT | |
| 297 |
SLAB_MEM_SPREAD, NULL); |
| 298 |
return (ulist_node_cachep) ? 0 : -ENOMEM; |
| 299 |
} |