0001
0002 #include <asm/bug.h>
0003 #include <linux/rbtree_augmented.h>
0004 #include "drbd_interval.h"
0005
0006
0007
0008
0009 static inline
0010 sector_t interval_end(struct rb_node *node)
0011 {
0012 struct drbd_interval *this = rb_entry(node, struct drbd_interval, rb);
0013 return this->end;
0014 }
0015
0016 #define NODE_END(node) ((node)->sector + ((node)->size >> 9))
0017
0018 RB_DECLARE_CALLBACKS_MAX(static, augment_callbacks,
0019 struct drbd_interval, rb, sector_t, end, NODE_END);
0020
0021
0022
0023
0024 bool
0025 drbd_insert_interval(struct rb_root *root, struct drbd_interval *this)
0026 {
0027 struct rb_node **new = &root->rb_node, *parent = NULL;
0028 sector_t this_end = this->sector + (this->size >> 9);
0029
0030 BUG_ON(!IS_ALIGNED(this->size, 512));
0031
0032 while (*new) {
0033 struct drbd_interval *here =
0034 rb_entry(*new, struct drbd_interval, rb);
0035
0036 parent = *new;
0037 if (here->end < this_end)
0038 here->end = this_end;
0039 if (this->sector < here->sector)
0040 new = &(*new)->rb_left;
0041 else if (this->sector > here->sector)
0042 new = &(*new)->rb_right;
0043 else if (this < here)
0044 new = &(*new)->rb_left;
0045 else if (this > here)
0046 new = &(*new)->rb_right;
0047 else
0048 return false;
0049 }
0050
0051 this->end = this_end;
0052 rb_link_node(&this->rb, parent, new);
0053 rb_insert_augmented(&this->rb, root, &augment_callbacks);
0054 return true;
0055 }
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068 bool
0069 drbd_contains_interval(struct rb_root *root, sector_t sector,
0070 struct drbd_interval *interval)
0071 {
0072 struct rb_node *node = root->rb_node;
0073
0074 while (node) {
0075 struct drbd_interval *here =
0076 rb_entry(node, struct drbd_interval, rb);
0077
0078 if (sector < here->sector)
0079 node = node->rb_left;
0080 else if (sector > here->sector)
0081 node = node->rb_right;
0082 else if (interval < here)
0083 node = node->rb_left;
0084 else if (interval > here)
0085 node = node->rb_right;
0086 else
0087 return true;
0088 }
0089 return false;
0090 }
0091
0092
0093
0094
0095 void
0096 drbd_remove_interval(struct rb_root *root, struct drbd_interval *this)
0097 {
0098 rb_erase_augmented(&this->rb, root, &augment_callbacks);
0099 }
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113 struct drbd_interval *
0114 drbd_find_overlap(struct rb_root *root, sector_t sector, unsigned int size)
0115 {
0116 struct rb_node *node = root->rb_node;
0117 struct drbd_interval *overlap = NULL;
0118 sector_t end = sector + (size >> 9);
0119
0120 BUG_ON(!IS_ALIGNED(size, 512));
0121
0122 while (node) {
0123 struct drbd_interval *here =
0124 rb_entry(node, struct drbd_interval, rb);
0125
0126 if (node->rb_left &&
0127 sector < interval_end(node->rb_left)) {
0128
0129 node = node->rb_left;
0130 } else if (here->sector < end &&
0131 sector < here->sector + (here->size >> 9)) {
0132 overlap = here;
0133 break;
0134 } else if (sector >= here->sector) {
0135
0136 node = node->rb_right;
0137 } else
0138 break;
0139 }
0140 return overlap;
0141 }
0142
0143 struct drbd_interval *
0144 drbd_next_overlap(struct drbd_interval *i, sector_t sector, unsigned int size)
0145 {
0146 sector_t end = sector + (size >> 9);
0147 struct rb_node *node;
0148
0149 for (;;) {
0150 node = rb_next(&i->rb);
0151 if (!node)
0152 return NULL;
0153 i = rb_entry(node, struct drbd_interval, rb);
0154 if (i->sector >= end)
0155 return NULL;
0156 if (sector < i->sector + (i->size >> 9))
0157 return i;
0158 }
0159 }