drbd_interval.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. #include <asm/bug.h>
  3. #include <linux/rbtree_augmented.h>
  4. #include "drbd_interval.h"
  5. /*
  6. * interval_end - return end of @node
  7. */
  8. static inline
  9. sector_t interval_end(struct rb_node *node)
  10. {
  11. struct drbd_interval *this = rb_entry(node, struct drbd_interval, rb);
  12. return this->end;
  13. }
  14. #define NODE_END(node) ((node)->sector + ((node)->size >> 9))
  15. RB_DECLARE_CALLBACKS_MAX(static, augment_callbacks,
  16. struct drbd_interval, rb, sector_t, end, NODE_END);
  17. /*
  18. * drbd_insert_interval - insert a new interval into a tree
  19. */
  20. bool
  21. drbd_insert_interval(struct rb_root *root, struct drbd_interval *this)
  22. {
  23. struct rb_node **new = &root->rb_node, *parent = NULL;
  24. sector_t this_end = this->sector + (this->size >> 9);
  25. BUG_ON(!IS_ALIGNED(this->size, 512));
  26. while (*new) {
  27. struct drbd_interval *here =
  28. rb_entry(*new, struct drbd_interval, rb);
  29. parent = *new;
  30. if (here->end < this_end)
  31. here->end = this_end;
  32. if (this->sector < here->sector)
  33. new = &(*new)->rb_left;
  34. else if (this->sector > here->sector)
  35. new = &(*new)->rb_right;
  36. else if (this < here)
  37. new = &(*new)->rb_left;
  38. else if (this > here)
  39. new = &(*new)->rb_right;
  40. else
  41. return false;
  42. }
  43. this->end = this_end;
  44. rb_link_node(&this->rb, parent, new);
  45. rb_insert_augmented(&this->rb, root, &augment_callbacks);
  46. return true;
  47. }
  48. /**
  49. * drbd_contains_interval - check if a tree contains a given interval
  50. * @root: red black tree root
  51. * @sector: start sector of @interval
  52. * @interval: may be an invalid pointer
  53. *
  54. * Returns if the tree contains the node @interval with start sector @start.
  55. * Does not dereference @interval until @interval is known to be a valid object
  56. * in @tree. Returns %false if @interval is in the tree but with a different
  57. * sector number.
  58. */
  59. bool
  60. drbd_contains_interval(struct rb_root *root, sector_t sector,
  61. struct drbd_interval *interval)
  62. {
  63. struct rb_node *node = root->rb_node;
  64. while (node) {
  65. struct drbd_interval *here =
  66. rb_entry(node, struct drbd_interval, rb);
  67. if (sector < here->sector)
  68. node = node->rb_left;
  69. else if (sector > here->sector)
  70. node = node->rb_right;
  71. else if (interval < here)
  72. node = node->rb_left;
  73. else if (interval > here)
  74. node = node->rb_right;
  75. else
  76. return true;
  77. }
  78. return false;
  79. }
  80. /*
  81. * drbd_remove_interval - remove an interval from a tree
  82. */
  83. void
  84. drbd_remove_interval(struct rb_root *root, struct drbd_interval *this)
  85. {
  86. /* avoid endless loop */
  87. if (drbd_interval_empty(this))
  88. return;
  89. rb_erase_augmented(&this->rb, root, &augment_callbacks);
  90. }
  91. /**
  92. * drbd_find_overlap - search for an interval overlapping with [sector, sector + size)
  93. * @root: red black tree root
  94. * @sector: start sector
  95. * @size: size, aligned to 512 bytes
  96. *
  97. * Returns an interval overlapping with [sector, sector + size), or NULL if
  98. * there is none. When there is more than one overlapping interval in the
  99. * tree, the interval with the lowest start sector is returned, and all other
  100. * overlapping intervals will be on the right side of the tree, reachable with
  101. * rb_next().
  102. */
  103. struct drbd_interval *
  104. drbd_find_overlap(struct rb_root *root, sector_t sector, unsigned int size)
  105. {
  106. struct rb_node *node = root->rb_node;
  107. struct drbd_interval *overlap = NULL;
  108. sector_t end = sector + (size >> 9);
  109. BUG_ON(!IS_ALIGNED(size, 512));
  110. while (node) {
  111. struct drbd_interval *here =
  112. rb_entry(node, struct drbd_interval, rb);
  113. if (node->rb_left &&
  114. sector < interval_end(node->rb_left)) {
  115. /* Overlap if any must be on left side */
  116. node = node->rb_left;
  117. } else if (here->sector < end &&
  118. sector < here->sector + (here->size >> 9)) {
  119. overlap = here;
  120. break;
  121. } else if (sector >= here->sector) {
  122. /* Overlap if any must be on right side */
  123. node = node->rb_right;
  124. } else
  125. break;
  126. }
  127. return overlap;
  128. }
  129. struct drbd_interval *
  130. drbd_next_overlap(struct drbd_interval *i, sector_t sector, unsigned int size)
  131. {
  132. sector_t end = sector + (size >> 9);
  133. struct rb_node *node;
  134. for (;;) {
  135. node = rb_next(&i->rb);
  136. if (!node)
  137. return NULL;
  138. i = rb_entry(node, struct drbd_interval, rb);
  139. if (i->sector >= end)
  140. return NULL;
  141. if (sector < i->sector + (i->size >> 9))
  142. return i;
  143. }
  144. }