162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <asm/bug.h> 362306a36Sopenharmony_ci#include <linux/rbtree_augmented.h> 462306a36Sopenharmony_ci#include "drbd_interval.h" 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci/* 762306a36Sopenharmony_ci * interval_end - return end of @node 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_cistatic inline 1062306a36Sopenharmony_cisector_t interval_end(struct rb_node *node) 1162306a36Sopenharmony_ci{ 1262306a36Sopenharmony_ci struct drbd_interval *this = rb_entry(node, struct drbd_interval, rb); 1362306a36Sopenharmony_ci return this->end; 1462306a36Sopenharmony_ci} 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define NODE_END(node) ((node)->sector + ((node)->size >> 9)) 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ciRB_DECLARE_CALLBACKS_MAX(static, augment_callbacks, 1962306a36Sopenharmony_ci struct drbd_interval, rb, sector_t, end, NODE_END); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* 2262306a36Sopenharmony_ci * drbd_insert_interval - insert a new interval into a tree 2362306a36Sopenharmony_ci */ 2462306a36Sopenharmony_cibool 2562306a36Sopenharmony_cidrbd_insert_interval(struct rb_root *root, struct drbd_interval *this) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct rb_node **new = &root->rb_node, *parent = NULL; 2862306a36Sopenharmony_ci sector_t this_end = this->sector + (this->size >> 9); 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci BUG_ON(!IS_ALIGNED(this->size, 512)); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci while (*new) { 3362306a36Sopenharmony_ci struct drbd_interval *here = 3462306a36Sopenharmony_ci rb_entry(*new, struct drbd_interval, rb); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci parent = *new; 3762306a36Sopenharmony_ci if (here->end < this_end) 3862306a36Sopenharmony_ci here->end = this_end; 3962306a36Sopenharmony_ci if (this->sector < here->sector) 4062306a36Sopenharmony_ci new = &(*new)->rb_left; 4162306a36Sopenharmony_ci else if (this->sector > here->sector) 4262306a36Sopenharmony_ci new = &(*new)->rb_right; 4362306a36Sopenharmony_ci else if (this < here) 4462306a36Sopenharmony_ci new = &(*new)->rb_left; 4562306a36Sopenharmony_ci else if (this > here) 4662306a36Sopenharmony_ci new = &(*new)->rb_right; 4762306a36Sopenharmony_ci else 4862306a36Sopenharmony_ci return false; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci this->end = this_end; 5262306a36Sopenharmony_ci rb_link_node(&this->rb, parent, new); 5362306a36Sopenharmony_ci rb_insert_augmented(&this->rb, root, &augment_callbacks); 5462306a36Sopenharmony_ci return true; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/** 5862306a36Sopenharmony_ci * drbd_contains_interval - check if a tree contains a given interval 5962306a36Sopenharmony_ci * @root: red black tree root 6062306a36Sopenharmony_ci * @sector: start sector of @interval 6162306a36Sopenharmony_ci * @interval: may be an invalid pointer 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * Returns if the tree contains the node @interval with start sector @start. 6462306a36Sopenharmony_ci * Does not dereference @interval until @interval is known to be a valid object 6562306a36Sopenharmony_ci * in @tree. Returns %false if @interval is in the tree but with a different 6662306a36Sopenharmony_ci * sector number. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_cibool 6962306a36Sopenharmony_cidrbd_contains_interval(struct rb_root *root, sector_t sector, 7062306a36Sopenharmony_ci struct drbd_interval *interval) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct rb_node *node = root->rb_node; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci while (node) { 7562306a36Sopenharmony_ci struct drbd_interval *here = 7662306a36Sopenharmony_ci rb_entry(node, struct drbd_interval, rb); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (sector < here->sector) 7962306a36Sopenharmony_ci node = node->rb_left; 8062306a36Sopenharmony_ci else if (sector > here->sector) 8162306a36Sopenharmony_ci node = node->rb_right; 8262306a36Sopenharmony_ci else if (interval < here) 8362306a36Sopenharmony_ci node = node->rb_left; 8462306a36Sopenharmony_ci else if (interval > here) 8562306a36Sopenharmony_ci node = node->rb_right; 8662306a36Sopenharmony_ci else 8762306a36Sopenharmony_ci return true; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci return false; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* 9362306a36Sopenharmony_ci * drbd_remove_interval - remove an interval from a tree 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_civoid 9662306a36Sopenharmony_cidrbd_remove_interval(struct rb_root *root, struct drbd_interval *this) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci /* avoid endless loop */ 9962306a36Sopenharmony_ci if (drbd_interval_empty(this)) 10062306a36Sopenharmony_ci return; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci rb_erase_augmented(&this->rb, root, &augment_callbacks); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/** 10662306a36Sopenharmony_ci * drbd_find_overlap - search for an interval overlapping with [sector, sector + size) 10762306a36Sopenharmony_ci * @root: red black tree root 10862306a36Sopenharmony_ci * @sector: start sector 10962306a36Sopenharmony_ci * @size: size, aligned to 512 bytes 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * Returns an interval overlapping with [sector, sector + size), or NULL if 11262306a36Sopenharmony_ci * there is none. When there is more than one overlapping interval in the 11362306a36Sopenharmony_ci * tree, the interval with the lowest start sector is returned, and all other 11462306a36Sopenharmony_ci * overlapping intervals will be on the right side of the tree, reachable with 11562306a36Sopenharmony_ci * rb_next(). 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_cistruct drbd_interval * 11862306a36Sopenharmony_cidrbd_find_overlap(struct rb_root *root, sector_t sector, unsigned int size) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci struct rb_node *node = root->rb_node; 12162306a36Sopenharmony_ci struct drbd_interval *overlap = NULL; 12262306a36Sopenharmony_ci sector_t end = sector + (size >> 9); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci BUG_ON(!IS_ALIGNED(size, 512)); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci while (node) { 12762306a36Sopenharmony_ci struct drbd_interval *here = 12862306a36Sopenharmony_ci rb_entry(node, struct drbd_interval, rb); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (node->rb_left && 13162306a36Sopenharmony_ci sector < interval_end(node->rb_left)) { 13262306a36Sopenharmony_ci /* Overlap if any must be on left side */ 13362306a36Sopenharmony_ci node = node->rb_left; 13462306a36Sopenharmony_ci } else if (here->sector < end && 13562306a36Sopenharmony_ci sector < here->sector + (here->size >> 9)) { 13662306a36Sopenharmony_ci overlap = here; 13762306a36Sopenharmony_ci break; 13862306a36Sopenharmony_ci } else if (sector >= here->sector) { 13962306a36Sopenharmony_ci /* Overlap if any must be on right side */ 14062306a36Sopenharmony_ci node = node->rb_right; 14162306a36Sopenharmony_ci } else 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci return overlap; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistruct drbd_interval * 14862306a36Sopenharmony_cidrbd_next_overlap(struct drbd_interval *i, sector_t sector, unsigned int size) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci sector_t end = sector + (size >> 9); 15162306a36Sopenharmony_ci struct rb_node *node; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci for (;;) { 15462306a36Sopenharmony_ci node = rb_next(&i->rb); 15562306a36Sopenharmony_ci if (!node) 15662306a36Sopenharmony_ci return NULL; 15762306a36Sopenharmony_ci i = rb_entry(node, struct drbd_interval, rb); 15862306a36Sopenharmony_ci if (i->sector >= end) 15962306a36Sopenharmony_ci return NULL; 16062306a36Sopenharmony_ci if (sector < i->sector + (i->size >> 9)) 16162306a36Sopenharmony_ci return i; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci} 164