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

interval_tree_generic.h (6863B)


      1/* SPDX-License-Identifier: GPL-2.0-or-later */
      2/*
      3  Interval Trees
      4  (C) 2012  Michel Lespinasse <walken@google.com>
      5
      6
      7  include/linux/interval_tree_generic.h
      8*/
      9
     10#include <linux/rbtree_augmented.h>
     11
     12/*
     13 * Template for implementing interval trees
     14 *
     15 * ITSTRUCT:   struct type of the interval tree nodes
     16 * ITRB:       name of struct rb_node field within ITSTRUCT
     17 * ITTYPE:     type of the interval endpoints
     18 * ITSUBTREE:  name of ITTYPE field within ITSTRUCT holding last-in-subtree
     19 * ITSTART(n): start endpoint of ITSTRUCT node n
     20 * ITLAST(n):  last endpoint of ITSTRUCT node n
     21 * ITSTATIC:   'static' or empty
     22 * ITPREFIX:   prefix to use for the inline tree definitions
     23 *
     24 * Note - before using this, please consider if generic version
     25 * (interval_tree.h) would work for you...
     26 */
     27
     28#define INTERVAL_TREE_DEFINE(ITSTRUCT, ITRB, ITTYPE, ITSUBTREE,		      \
     29			     ITSTART, ITLAST, ITSTATIC, ITPREFIX)	      \
     30									      \
     31/* Callbacks for augmented rbtree insert and remove */			      \
     32									      \
     33RB_DECLARE_CALLBACKS_MAX(static, ITPREFIX ## _augment,			      \
     34			 ITSTRUCT, ITRB, ITTYPE, ITSUBTREE, ITLAST)	      \
     35									      \
     36/* Insert / remove interval nodes from the tree */			      \
     37									      \
     38ITSTATIC void ITPREFIX ## _insert(ITSTRUCT *node,			      \
     39				  struct rb_root_cached *root)	 	      \
     40{									      \
     41	struct rb_node **link = &root->rb_root.rb_node, *rb_parent = NULL;    \
     42	ITTYPE start = ITSTART(node), last = ITLAST(node);		      \
     43	ITSTRUCT *parent;						      \
     44	bool leftmost = true;						      \
     45									      \
     46	while (*link) {							      \
     47		rb_parent = *link;					      \
     48		parent = rb_entry(rb_parent, ITSTRUCT, ITRB);		      \
     49		if (parent->ITSUBTREE < last)				      \
     50			parent->ITSUBTREE = last;			      \
     51		if (start < ITSTART(parent))				      \
     52			link = &parent->ITRB.rb_left;			      \
     53		else {							      \
     54			link = &parent->ITRB.rb_right;			      \
     55			leftmost = false;				      \
     56		}							      \
     57	}								      \
     58									      \
     59	node->ITSUBTREE = last;						      \
     60	rb_link_node(&node->ITRB, rb_parent, link);			      \
     61	rb_insert_augmented_cached(&node->ITRB, root,			      \
     62				   leftmost, &ITPREFIX ## _augment);	      \
     63}									      \
     64									      \
     65ITSTATIC void ITPREFIX ## _remove(ITSTRUCT *node,			      \
     66				  struct rb_root_cached *root)		      \
     67{									      \
     68	rb_erase_augmented_cached(&node->ITRB, root, &ITPREFIX ## _augment);  \
     69}									      \
     70									      \
     71/*									      \
     72 * Iterate over intervals intersecting [start;last]			      \
     73 *									      \
     74 * Note that a node's interval intersects [start;last] iff:		      \
     75 *   Cond1: ITSTART(node) <= last					      \
     76 * and									      \
     77 *   Cond2: start <= ITLAST(node)					      \
     78 */									      \
     79									      \
     80static ITSTRUCT *							      \
     81ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last)	      \
     82{									      \
     83	while (true) {							      \
     84		/*							      \
     85		 * Loop invariant: start <= node->ITSUBTREE		      \
     86		 * (Cond2 is satisfied by one of the subtree nodes)	      \
     87		 */							      \
     88		if (node->ITRB.rb_left) {				      \
     89			ITSTRUCT *left = rb_entry(node->ITRB.rb_left,	      \
     90						  ITSTRUCT, ITRB);	      \
     91			if (start <= left->ITSUBTREE) {			      \
     92				/*					      \
     93				 * Some nodes in left subtree satisfy Cond2.  \
     94				 * Iterate to find the leftmost such node N.  \
     95				 * If it also satisfies Cond1, that's the     \
     96				 * match we are looking for. Otherwise, there \
     97				 * is no matching interval as nodes to the    \
     98				 * right of N can't satisfy Cond1 either.     \
     99				 */					      \
    100				node = left;				      \
    101				continue;				      \
    102			}						      \
    103		}							      \
    104		if (ITSTART(node) <= last) {		/* Cond1 */	      \
    105			if (start <= ITLAST(node))	/* Cond2 */	      \
    106				return node;	/* node is leftmost match */  \
    107			if (node->ITRB.rb_right) {			      \
    108				node = rb_entry(node->ITRB.rb_right,	      \
    109						ITSTRUCT, ITRB);	      \
    110				if (start <= node->ITSUBTREE)		      \
    111					continue;			      \
    112			}						      \
    113		}							      \
    114		return NULL;	/* No match */				      \
    115	}								      \
    116}									      \
    117									      \
    118ITSTATIC ITSTRUCT *							      \
    119ITPREFIX ## _iter_first(struct rb_root_cached *root,			      \
    120			ITTYPE start, ITTYPE last)			      \
    121{									      \
    122	ITSTRUCT *node, *leftmost;					      \
    123									      \
    124	if (!root->rb_root.rb_node)					      \
    125		return NULL;						      \
    126									      \
    127	/*								      \
    128	 * Fastpath range intersection/overlap between A: [a0, a1] and	      \
    129	 * B: [b0, b1] is given by:					      \
    130	 *								      \
    131	 *         a0 <= b1 && b0 <= a1					      \
    132	 *								      \
    133	 *  ... where A holds the lock range and B holds the smallest	      \
    134	 * 'start' and largest 'last' in the tree. For the later, we	      \
    135	 * rely on the root node, which by augmented interval tree	      \
    136	 * property, holds the largest value in its last-in-subtree.	      \
    137	 * This allows mitigating some of the tree walk overhead for	      \
    138	 * for non-intersecting ranges, maintained and consulted in O(1).     \
    139	 */								      \
    140	node = rb_entry(root->rb_root.rb_node, ITSTRUCT, ITRB);		      \
    141	if (node->ITSUBTREE < start)					      \
    142		return NULL;						      \
    143									      \
    144	leftmost = rb_entry(root->rb_leftmost, ITSTRUCT, ITRB);		      \
    145	if (ITSTART(leftmost) > last)					      \
    146		return NULL;						      \
    147									      \
    148	return ITPREFIX ## _subtree_search(node, start, last);		      \
    149}									      \
    150									      \
    151ITSTATIC ITSTRUCT *							      \
    152ITPREFIX ## _iter_next(ITSTRUCT *node, ITTYPE start, ITTYPE last)	      \
    153{									      \
    154	struct rb_node *rb = node->ITRB.rb_right, *prev;		      \
    155									      \
    156	while (true) {							      \
    157		/*							      \
    158		 * Loop invariants:					      \
    159		 *   Cond1: ITSTART(node) <= last			      \
    160		 *   rb == node->ITRB.rb_right				      \
    161		 *							      \
    162		 * First, search right subtree if suitable		      \
    163		 */							      \
    164		if (rb) {						      \
    165			ITSTRUCT *right = rb_entry(rb, ITSTRUCT, ITRB);	      \
    166			if (start <= right->ITSUBTREE)			      \
    167				return ITPREFIX ## _subtree_search(right,     \
    168								start, last); \
    169		}							      \
    170									      \
    171		/* Move up the tree until we come from a node's left child */ \
    172		do {							      \
    173			rb = rb_parent(&node->ITRB);			      \
    174			if (!rb)					      \
    175				return NULL;				      \
    176			prev = &node->ITRB;				      \
    177			node = rb_entry(rb, ITSTRUCT, ITRB);		      \
    178			rb = node->ITRB.rb_right;			      \
    179		} while (prev == rb);					      \
    180									      \
    181		/* Check if the node intersects [start;last] */		      \
    182		if (last < ITSTART(node))		/* !Cond1 */	      \
    183			return NULL;					      \
    184		else if (start <= ITLAST(node))		/* Cond2 */	      \
    185			return node;					      \
    186	}								      \
    187}