cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ulist.c (6879B)


      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 "ulist.h"
      9#include "ctree.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 * ulist_init - freshly initialize a ulist
     42 * @ulist:	the ulist to initialize
     43 *
     44 * Note: don't use this function to init an already used ulist, use
     45 * ulist_reinit instead.
     46 */
     47void ulist_init(struct ulist *ulist)
     48{
     49	INIT_LIST_HEAD(&ulist->nodes);
     50	ulist->root = RB_ROOT;
     51	ulist->nnodes = 0;
     52}
     53
     54/**
     55 * ulist_release - free up additionally allocated memory for the ulist
     56 * @ulist:	the ulist from which to free the additional memory
     57 *
     58 * This is useful in cases where the base 'struct ulist' has been statically
     59 * allocated.
     60 */
     61void ulist_release(struct ulist *ulist)
     62{
     63	struct ulist_node *node;
     64	struct ulist_node *next;
     65
     66	list_for_each_entry_safe(node, next, &ulist->nodes, list) {
     67		kfree(node);
     68	}
     69	ulist->root = RB_ROOT;
     70	INIT_LIST_HEAD(&ulist->nodes);
     71}
     72
     73/**
     74 * ulist_reinit - prepare a ulist for reuse
     75 * @ulist:	ulist to be reused
     76 *
     77 * Free up all additional memory allocated for the list elements and reinit
     78 * the ulist.
     79 */
     80void ulist_reinit(struct ulist *ulist)
     81{
     82	ulist_release(ulist);
     83	ulist_init(ulist);
     84}
     85
     86/**
     87 * ulist_alloc - dynamically allocate a ulist
     88 * @gfp_mask:	allocation flags to for base allocation
     89 *
     90 * The allocated ulist will be returned in an initialized state.
     91 */
     92struct ulist *ulist_alloc(gfp_t gfp_mask)
     93{
     94	struct ulist *ulist = kmalloc(sizeof(*ulist), gfp_mask);
     95
     96	if (!ulist)
     97		return NULL;
     98
     99	ulist_init(ulist);
    100
    101	return ulist;
    102}
    103
    104/**
    105 * ulist_free - free dynamically allocated ulist
    106 * @ulist:	ulist to free
    107 *
    108 * It is not necessary to call ulist_release before.
    109 */
    110void ulist_free(struct ulist *ulist)
    111{
    112	if (!ulist)
    113		return;
    114	ulist_release(ulist);
    115	kfree(ulist);
    116}
    117
    118static struct ulist_node *ulist_rbtree_search(struct ulist *ulist, u64 val)
    119{
    120	struct rb_node *n = ulist->root.rb_node;
    121	struct ulist_node *u = NULL;
    122
    123	while (n) {
    124		u = rb_entry(n, struct ulist_node, rb_node);
    125		if (u->val < val)
    126			n = n->rb_right;
    127		else if (u->val > val)
    128			n = n->rb_left;
    129		else
    130			return u;
    131	}
    132	return NULL;
    133}
    134
    135static void ulist_rbtree_erase(struct ulist *ulist, struct ulist_node *node)
    136{
    137	rb_erase(&node->rb_node, &ulist->root);
    138	list_del(&node->list);
    139	kfree(node);
    140	BUG_ON(ulist->nnodes == 0);
    141	ulist->nnodes--;
    142}
    143
    144static int ulist_rbtree_insert(struct ulist *ulist, struct ulist_node *ins)
    145{
    146	struct rb_node **p = &ulist->root.rb_node;
    147	struct rb_node *parent = NULL;
    148	struct ulist_node *cur = NULL;
    149
    150	while (*p) {
    151		parent = *p;
    152		cur = rb_entry(parent, struct ulist_node, rb_node);
    153
    154		if (cur->val < ins->val)
    155			p = &(*p)->rb_right;
    156		else if (cur->val > ins->val)
    157			p = &(*p)->rb_left;
    158		else
    159			return -EEXIST;
    160	}
    161	rb_link_node(&ins->rb_node, parent, p);
    162	rb_insert_color(&ins->rb_node, &ulist->root);
    163	return 0;
    164}
    165
    166/**
    167 * ulist_add - add an element to the ulist
    168 * @ulist:	ulist to add the element to
    169 * @val:	value to add to ulist
    170 * @aux:	auxiliary value to store along with val
    171 * @gfp_mask:	flags to use for allocation
    172 *
    173 * Note: locking must be provided by the caller. In case of rwlocks write
    174 *       locking is needed
    175 *
    176 * Add an element to a ulist. The @val will only be added if it doesn't
    177 * already exist. If it is added, the auxiliary value @aux is stored along with
    178 * it. In case @val already exists in the ulist, @aux is ignored, even if
    179 * it differs from the already stored value.
    180 *
    181 * ulist_add returns 0 if @val already exists in ulist and 1 if @val has been
    182 * inserted.
    183 * In case of allocation failure -ENOMEM is returned and the ulist stays
    184 * unaltered.
    185 */
    186int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask)
    187{
    188	return ulist_add_merge(ulist, val, aux, NULL, gfp_mask);
    189}
    190
    191int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux,
    192		    u64 *old_aux, gfp_t gfp_mask)
    193{
    194	int ret;
    195	struct ulist_node *node;
    196
    197	node = ulist_rbtree_search(ulist, val);
    198	if (node) {
    199		if (old_aux)
    200			*old_aux = node->aux;
    201		return 0;
    202	}
    203	node = kmalloc(sizeof(*node), gfp_mask);
    204	if (!node)
    205		return -ENOMEM;
    206
    207	node->val = val;
    208	node->aux = aux;
    209
    210	ret = ulist_rbtree_insert(ulist, node);
    211	ASSERT(!ret);
    212	list_add_tail(&node->list, &ulist->nodes);
    213	ulist->nnodes++;
    214
    215	return 1;
    216}
    217
    218/*
    219 * ulist_del - delete one node from ulist
    220 * @ulist:	ulist to remove node from
    221 * @val:	value to delete
    222 * @aux:	aux to delete
    223 *
    224 * The deletion will only be done when *BOTH* val and aux matches.
    225 * Return 0 for successful delete.
    226 * Return > 0 for not found.
    227 */
    228int ulist_del(struct ulist *ulist, u64 val, u64 aux)
    229{
    230	struct ulist_node *node;
    231
    232	node = ulist_rbtree_search(ulist, val);
    233	/* Not found */
    234	if (!node)
    235		return 1;
    236
    237	if (node->aux != aux)
    238		return 1;
    239
    240	/* Found and delete */
    241	ulist_rbtree_erase(ulist, node);
    242	return 0;
    243}
    244
    245/**
    246 * ulist_next - iterate ulist
    247 * @ulist:	ulist to iterate
    248 * @uiter:	iterator variable, initialized with ULIST_ITER_INIT(&iterator)
    249 *
    250 * Note: locking must be provided by the caller. In case of rwlocks only read
    251 *       locking is needed
    252 *
    253 * This function is used to iterate an ulist.
    254 * It returns the next element from the ulist or %NULL when the
    255 * end is reached. No guarantee is made with respect to the order in which
    256 * the elements are returned. They might neither be returned in order of
    257 * addition nor in ascending order.
    258 * It is allowed to call ulist_add during an enumeration. Newly added items
    259 * are guaranteed to show up in the running enumeration.
    260 */
    261struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_iterator *uiter)
    262{
    263	struct ulist_node *node;
    264
    265	if (list_empty(&ulist->nodes))
    266		return NULL;
    267	if (uiter->cur_list && uiter->cur_list->next == &ulist->nodes)
    268		return NULL;
    269	if (uiter->cur_list) {
    270		uiter->cur_list = uiter->cur_list->next;
    271	} else {
    272		uiter->cur_list = ulist->nodes.next;
    273	}
    274	node = list_entry(uiter->cur_list, struct ulist_node, list);
    275	return node;
    276}