Blame view
fs/btrfs/ulist.c
6.72 KB
c1d7c514f btrfs: replace GP... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
da5c81356 Btrfs: generic da... |
2 3 4 |
/* * Copyright (C) 2011 STRATO AG * written by Arne Jansen <sensille@gmx.net> |
da5c81356 Btrfs: generic da... |
5 6 7 |
*/ #include <linux/slab.h> |
da5c81356 Btrfs: generic da... |
8 |
#include "ulist.h" |
4c7a6f74c Btrfs: rework uli... |
9 |
#include "ctree.h" |
da5c81356 Btrfs: generic da... |
10 11 12 13 14 15 16 |
/* * ulist is a generic data structure to hold a collection of unique u64 * values. The only operations it supports is adding to the list and * enumerating it. * It is possible to store an auxiliary value along with the key. * |
da5c81356 Btrfs: generic da... |
17 18 19 20 21 |
* A sample usage for ulists is the enumeration of directed graphs without * visiting a node twice. The pseudo-code could look like this: * * ulist = ulist_alloc(); * ulist_add(ulist, root); |
cd1b413c5 Btrfs: ulist real... |
22 |
* ULIST_ITER_INIT(&uiter); |
da5c81356 Btrfs: generic da... |
23 |
* |
cd1b413c5 Btrfs: ulist real... |
24 |
* while ((elem = ulist_next(ulist, &uiter)) { |
da5c81356 Btrfs: generic da... |
25 26 27 28 29 30 |
* for (all child nodes n in elem) * ulist_add(ulist, n); * do something useful with the node; * } * ulist_free(ulist); * |
013276101 btrfs: fix string... |
31 |
* This assumes the graph nodes are addressable by u64. This stems from the |
da5c81356 Btrfs: generic da... |
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
* usage for tree enumeration in btrfs, where the logical addresses are * 64 bit. * * It is also useful for tree enumeration which could be done elegantly * recursively, but is not possible due to kernel stack limitations. The * loop would be similar to the above. */ /** * ulist_init - freshly initialize a ulist * @ulist: the ulist to initialize * * Note: don't use this function to init an already used ulist, use * ulist_reinit instead. */ void ulist_init(struct ulist *ulist) { |
4c7a6f74c Btrfs: rework uli... |
49 |
INIT_LIST_HEAD(&ulist->nodes); |
f7f82b81d Btrfs: add a rb_t... |
50 |
ulist->root = RB_ROOT; |
4c7a6f74c Btrfs: rework uli... |
51 |
ulist->nnodes = 0; |
da5c81356 Btrfs: generic da... |
52 |
} |
da5c81356 Btrfs: generic da... |
53 54 |
/** |
6655bc3de btrfs: ulist: ren... |
55 |
* ulist_release - free up additionally allocated memory for the ulist |
da5c81356 Btrfs: generic da... |
56 57 58 59 60 |
* @ulist: the ulist from which to free the additional memory * * This is useful in cases where the base 'struct ulist' has been statically * allocated. */ |
6655bc3de btrfs: ulist: ren... |
61 |
void ulist_release(struct ulist *ulist) |
da5c81356 Btrfs: generic da... |
62 |
{ |
4c7a6f74c Btrfs: rework uli... |
63 64 65 66 67 68 |
struct ulist_node *node; struct ulist_node *next; list_for_each_entry_safe(node, next, &ulist->nodes, list) { kfree(node); } |
f7f82b81d Btrfs: add a rb_t... |
69 |
ulist->root = RB_ROOT; |
4c7a6f74c Btrfs: rework uli... |
70 |
INIT_LIST_HEAD(&ulist->nodes); |
da5c81356 Btrfs: generic da... |
71 |
} |
da5c81356 Btrfs: generic da... |
72 73 74 75 76 77 78 79 80 81 |
/** * ulist_reinit - prepare a ulist for reuse * @ulist: ulist to be reused * * Free up all additional memory allocated for the list elements and reinit * the ulist. */ void ulist_reinit(struct ulist *ulist) { |
6655bc3de btrfs: ulist: ren... |
82 |
ulist_release(ulist); |
da5c81356 Btrfs: generic da... |
83 84 |
ulist_init(ulist); } |
da5c81356 Btrfs: generic da... |
85 86 87 88 89 90 91 |
/** * ulist_alloc - dynamically allocate a ulist * @gfp_mask: allocation flags to for base allocation * * The allocated ulist will be returned in an initialized state. */ |
2eec6c810 Fix minor type is... |
92 |
struct ulist *ulist_alloc(gfp_t gfp_mask) |
da5c81356 Btrfs: generic da... |
93 94 95 96 97 98 99 100 101 102 |
{ struct ulist *ulist = kmalloc(sizeof(*ulist), gfp_mask); if (!ulist) return NULL; ulist_init(ulist); return ulist; } |
da5c81356 Btrfs: generic da... |
103 104 105 106 107 |
/** * ulist_free - free dynamically allocated ulist * @ulist: ulist to free * |
6655bc3de btrfs: ulist: ren... |
108 |
* It is not necessary to call ulist_release before. |
da5c81356 Btrfs: generic da... |
109 110 111 112 113 |
*/ void ulist_free(struct ulist *ulist) { if (!ulist) return; |
6655bc3de btrfs: ulist: ren... |
114 |
ulist_release(ulist); |
da5c81356 Btrfs: generic da... |
115 116 |
kfree(ulist); } |
da5c81356 Btrfs: generic da... |
117 |
|
f7f82b81d Btrfs: add a rb_t... |
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
static struct ulist_node *ulist_rbtree_search(struct ulist *ulist, u64 val) { struct rb_node *n = ulist->root.rb_node; struct ulist_node *u = NULL; while (n) { u = rb_entry(n, struct ulist_node, rb_node); if (u->val < val) n = n->rb_right; else if (u->val > val) n = n->rb_left; else return u; } return NULL; } |
d4b804045 btrfs: ulist: Add... |
134 135 136 137 138 139 140 141 |
static void ulist_rbtree_erase(struct ulist *ulist, struct ulist_node *node) { rb_erase(&node->rb_node, &ulist->root); list_del(&node->list); kfree(node); BUG_ON(ulist->nnodes == 0); ulist->nnodes--; } |
f7f82b81d Btrfs: add a rb_t... |
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
static int ulist_rbtree_insert(struct ulist *ulist, struct ulist_node *ins) { struct rb_node **p = &ulist->root.rb_node; struct rb_node *parent = NULL; struct ulist_node *cur = NULL; while (*p) { parent = *p; cur = rb_entry(parent, struct ulist_node, rb_node); if (cur->val < ins->val) p = &(*p)->rb_right; else if (cur->val > ins->val) p = &(*p)->rb_left; else return -EEXIST; } rb_link_node(&ins->rb_node, parent, p); rb_insert_color(&ins->rb_node, &ulist->root); return 0; } |
da5c81356 Btrfs: generic da... |
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
/** * ulist_add - add an element to the ulist * @ulist: ulist to add the element to * @val: value to add to ulist * @aux: auxiliary value to store along with val * @gfp_mask: flags to use for allocation * * Note: locking must be provided by the caller. In case of rwlocks write * locking is needed * * Add an element to a ulist. The @val will only be added if it doesn't * already exist. If it is added, the auxiliary value @aux is stored along with * it. In case @val already exists in the ulist, @aux is ignored, even if * it differs from the already stored value. * * ulist_add returns 0 if @val already exists in ulist and 1 if @val has been * inserted. * In case of allocation failure -ENOMEM is returned and the ulist stays * unaltered. */ |
34d73f54e Btrfs: make aux f... |
183 |
int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask) |
da5c81356 Btrfs: generic da... |
184 |
{ |
3301958b7 Btrfs: add inodes... |
185 186 |
return ulist_add_merge(ulist, val, aux, NULL, gfp_mask); } |
34d73f54e Btrfs: make aux f... |
187 188 |
int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, u64 *old_aux, gfp_t gfp_mask) |
3301958b7 Btrfs: add inodes... |
189 |
{ |
4c7a6f74c Btrfs: rework uli... |
190 191 |
int ret; struct ulist_node *node; |
f7f82b81d Btrfs: add a rb_t... |
192 193 194 195 196 |
node = ulist_rbtree_search(ulist, val); if (node) { if (old_aux) *old_aux = node->aux; return 0; |
da5c81356 Btrfs: generic da... |
197 |
} |
4c7a6f74c Btrfs: rework uli... |
198 199 200 |
node = kmalloc(sizeof(*node), gfp_mask); if (!node) return -ENOMEM; |
da5c81356 Btrfs: generic da... |
201 |
|
4c7a6f74c Btrfs: rework uli... |
202 203 |
node->val = val; node->aux = aux; |
da5c81356 Btrfs: generic da... |
204 |
|
4c7a6f74c Btrfs: rework uli... |
205 206 207 208 |
ret = ulist_rbtree_insert(ulist, node); ASSERT(!ret); list_add_tail(&node->list, &ulist->nodes); ulist->nnodes++; |
da5c81356 Btrfs: generic da... |
209 210 211 |
return 1; } |
da5c81356 Btrfs: generic da... |
212 |
|
d4b804045 btrfs: ulist: Add... |
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
/* * ulist_del - delete one node from ulist * @ulist: ulist to remove node from * @val: value to delete * @aux: aux to delete * * The deletion will only be done when *BOTH* val and aux matches. * Return 0 for successful delete. * Return > 0 for not found. */ int ulist_del(struct ulist *ulist, u64 val, u64 aux) { struct ulist_node *node; node = ulist_rbtree_search(ulist, val); /* Not found */ if (!node) return 1; if (node->aux != aux) return 1; /* Found and delete */ ulist_rbtree_erase(ulist, node); return 0; } |
da5c81356 Btrfs: generic da... |
239 240 241 |
/** * ulist_next - iterate ulist * @ulist: ulist to iterate |
cd1b413c5 Btrfs: ulist real... |
242 |
* @uiter: iterator variable, initialized with ULIST_ITER_INIT(&iterator) |
da5c81356 Btrfs: generic da... |
243 244 245 246 |
* * Note: locking must be provided by the caller. In case of rwlocks only read * locking is needed * |
cd1b413c5 Btrfs: ulist real... |
247 248 |
* This function is used to iterate an ulist. * It returns the next element from the ulist or %NULL when the |
da5c81356 Btrfs: generic da... |
249 250 251 252 253 254 |
* end is reached. No guarantee is made with respect to the order in which * the elements are returned. They might neither be returned in order of * addition nor in ascending order. * It is allowed to call ulist_add during an enumeration. Newly added items * are guaranteed to show up in the running enumeration. */ |
cd1b413c5 Btrfs: ulist real... |
255 |
struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_iterator *uiter) |
da5c81356 Btrfs: generic da... |
256 |
{ |
4c7a6f74c Btrfs: rework uli... |
257 258 259 |
struct ulist_node *node; if (list_empty(&ulist->nodes)) |
da5c81356 Btrfs: generic da... |
260 |
return NULL; |
4c7a6f74c Btrfs: rework uli... |
261 |
if (uiter->cur_list && uiter->cur_list->next == &ulist->nodes) |
da5c81356 Btrfs: generic da... |
262 |
return NULL; |
4c7a6f74c Btrfs: rework uli... |
263 264 265 266 |
if (uiter->cur_list) { uiter->cur_list = uiter->cur_list->next; } else { uiter->cur_list = ulist->nodes.next; |
4c7a6f74c Btrfs: rework uli... |
267 268 |
} node = list_entry(uiter->cur_list, struct ulist_node, list); |
4c7a6f74c Btrfs: rework uli... |
269 |
return node; |
da5c81356 Btrfs: generic da... |
270 |
} |