~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/btrfs/ulist.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php