drbd_interval.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // SPDX-License-Identifier: GPL-2.0
  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 not be a valid 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. rb_erase_augmented(&this->rb, root, &augment_callbacks);
  87. }
  88. /**
  89. * drbd_find_overlap - search for an interval overlapping with [sector, sector + size)
  90. * @root: red black tree root
  91. * @sector: start sector
  92. * @size: size, aligned to 512 bytes
  93. *
  94. * Returns an interval overlapping with [sector, sector + size), or NULL if
  95. * there is none. When there is more than one overlapping interval in the
  96. * tree, the interval with the lowest start sector is returned, and all other
  97. * overlapping intervals will be on the right side of the tree, reachable with
  98. * rb_next().
  99. */
  100. struct drbd_interval *
  101. drbd_find_overlap(struct rb_root *root, sector_t sector, unsigned int size)
  102. {
  103. struct rb_node *node = root->rb_node;
  104. struct drbd_interval *overlap = NULL;
  105. sector_t end = sector + (size >> 9);
  106. BUG_ON(!IS_ALIGNED(size, 512));
  107. while (node) {
  108. struct drbd_interval *here =
  109. rb_entry(node, struct drbd_interval, rb);
  110. if (node->rb_left &&
  111. sector < interval_end(node->rb_left)) {
  112. /* Overlap if any must be on left side */
  113. node = node->rb_left;
  114. } else if (here->sector < end &&
  115. sector < here->sector + (here->size >> 9)) {
  116. overlap = here;
  117. break;
  118. } else if (sector >= here->sector) {
  119. /* Overlap if any must be on right side */
  120. node = node->rb_right;
  121. } else
  122. break;
  123. }
  124. return overlap;
  125. }
  126. struct drbd_interval *
  127. drbd_next_overlap(struct drbd_interval *i, sector_t sector, unsigned int size)
  128. {
  129. sector_t end = sector + (size >> 9);
  130. struct rb_node *node;
  131. for (;;) {
  132. node = rb_next(&i->rb);
  133. if (!node)
  134. return NULL;
  135. i = rb_entry(node, struct drbd_interval, rb);
  136. if (i->sector >= end)
  137. return NULL;
  138. if (sector < i->sector + (i->size >> 9))
  139. return i;
  140. }
  141. }