drbd_interval.c revision 3e05146f0a9f28ef5959403eabf3239869476315
1#include "drbd_interval.h" 2 3/** 4 * interval_end - return end of @node 5 */ 6static inline 7sector_t interval_end(struct rb_node *node) 8{ 9 struct drbd_interval *this = rb_entry(node, struct drbd_interval, rb); 10 return this->end; 11} 12 13/** 14 * update_interval_end - recompute end of @node 15 * 16 * The end of an interval is the highest (start + (size >> 9)) value of this 17 * node and of its children. Called for @node and its parents whenever the end 18 * may have changed. 19 */ 20static void 21update_interval_end(struct rb_node *node, void *__unused) 22{ 23 struct drbd_interval *this = rb_entry(node, struct drbd_interval, rb); 24 sector_t end; 25 26 end = this->sector + (this->size >> 9); 27 if (node->rb_left) { 28 sector_t left = interval_end(node->rb_left); 29 if (left > end) 30 end = left; 31 } 32 if (node->rb_right) { 33 sector_t right = interval_end(node->rb_right); 34 if (right > end) 35 end = right; 36 } 37 this->end = end; 38} 39 40/** 41 * drbd_insert_interval - insert a new interval into a tree 42 */ 43bool 44drbd_insert_interval(struct rb_root *root, struct drbd_interval *this) 45{ 46 struct rb_node **new = &root->rb_node, *parent = NULL; 47 48 BUG_ON(!IS_ALIGNED(this->size, 512)); 49 50 while (*new) { 51 struct drbd_interval *here = 52 rb_entry(*new, struct drbd_interval, rb); 53 54 parent = *new; 55 if (this->sector < here->sector) 56 new = &(*new)->rb_left; 57 else if (this->sector > here->sector) 58 new = &(*new)->rb_right; 59 else if (this < here) 60 new = &(*new)->rb_left; 61 else if (this > here) 62 new = &(*new)->rb_right; 63 else 64 return false; 65 } 66 67 rb_link_node(&this->rb, parent, new); 68 rb_insert_color(&this->rb, root); 69 rb_augment_insert(&this->rb, update_interval_end, NULL); 70 return true; 71} 72 73/** 74 * drbd_contains_interval - check if a tree contains a given interval 75 * @sector: start sector of @interval 76 * @interval: may not be a valid pointer 77 * 78 * Returns if the tree contains the node @interval with start sector @start. 79 * Does not dereference @interval until @interval is known to be a valid object 80 * in @tree. Returns %false if @interval is in the tree but with a different 81 * sector number. 82 */ 83bool 84drbd_contains_interval(struct rb_root *root, sector_t sector, 85 struct drbd_interval *interval) 86{ 87 struct rb_node *node = root->rb_node; 88 89 while (node) { 90 struct drbd_interval *here = 91 rb_entry(node, struct drbd_interval, rb); 92 93 if (sector < here->sector) 94 node = node->rb_left; 95 else if (sector > here->sector) 96 node = node->rb_right; 97 else if (interval < here) 98 node = node->rb_left; 99 else if (interval > here) 100 node = node->rb_right; 101 else 102 return true; 103 } 104 return false; 105} 106 107/** 108 * drbd_remove_interval - remove an interval from a tree 109 */ 110void 111drbd_remove_interval(struct rb_root *root, struct drbd_interval *this) 112{ 113 struct rb_node *deepest; 114 115 deepest = rb_augment_erase_begin(&this->rb); 116 rb_erase(&this->rb, root); 117 rb_augment_erase_end(deepest, update_interval_end, NULL); 118} 119 120/** 121 * drbd_find_overlap - search for an interval overlapping with [sector, sector + size) 122 * @sector: start sector 123 * @size: size, aligned to 512 bytes 124 * 125 * Returns the interval overlapping with [sector, sector + size), or NULL. 126 * When there is more than one overlapping interval in the tree, the interval 127 * with the lowest start sector is returned. 128 */ 129struct drbd_interval * 130drbd_find_overlap(struct rb_root *root, sector_t sector, unsigned int size) 131{ 132 struct rb_node *node = root->rb_node; 133 struct drbd_interval *overlap = NULL; 134 sector_t end = sector + (size >> 9); 135 136 BUG_ON(!IS_ALIGNED(size, 512)); 137 138 while (node) { 139 struct drbd_interval *here = 140 rb_entry(node, struct drbd_interval, rb); 141 142 if (node->rb_left && 143 sector < interval_end(node->rb_left)) { 144 /* Overlap if any must be on left side */ 145 node = node->rb_left; 146 } else if (here->sector < end && 147 sector < here->sector + (here->size >> 9)) { 148 overlap = here; 149 break; 150 } else if (sector >= here->sector) { 151 /* Overlap if any must be on right side */ 152 node = node->rb_right; 153 } else 154 break; 155 } 156 return overlap; 157} 158