diff options
Diffstat (limited to 'lib/radix-tree.c')
-rw-r--r-- | lib/radix-tree.c | 138 |
1 files changed, 121 insertions, 17 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c index dbf4e8c8e100..0a7ac0fb4a65 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c | |||
@@ -69,6 +69,11 @@ struct radix_tree_preload { | |||
69 | }; | 69 | }; |
70 | static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; | 70 | static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; |
71 | 71 | ||
72 | static inline struct radix_tree_node *entry_to_node(void *ptr) | ||
73 | { | ||
74 | return (void *)((unsigned long)ptr & ~RADIX_TREE_INTERNAL_NODE); | ||
75 | } | ||
76 | |||
72 | static inline void *node_to_entry(void *ptr) | 77 | static inline void *node_to_entry(void *ptr) |
73 | { | 78 | { |
74 | return (void *)((unsigned long)ptr | RADIX_TREE_INTERNAL_NODE); | 79 | return (void *)((unsigned long)ptr | RADIX_TREE_INTERNAL_NODE); |
@@ -1104,6 +1109,120 @@ static inline void __set_iter_shift(struct radix_tree_iter *iter, | |||
1104 | #endif | 1109 | #endif |
1105 | } | 1110 | } |
1106 | 1111 | ||
1112 | /* Construct iter->tags bit-mask from node->tags[tag] array */ | ||
1113 | static void set_iter_tags(struct radix_tree_iter *iter, | ||
1114 | struct radix_tree_node *node, unsigned offset, | ||
1115 | unsigned tag) | ||
1116 | { | ||
1117 | unsigned tag_long = offset / BITS_PER_LONG; | ||
1118 | unsigned tag_bit = offset % BITS_PER_LONG; | ||
1119 | |||
1120 | iter->tags = node->tags[tag][tag_long] >> tag_bit; | ||
1121 | |||
1122 | /* This never happens if RADIX_TREE_TAG_LONGS == 1 */ | ||
1123 | if (tag_long < RADIX_TREE_TAG_LONGS - 1) { | ||
1124 | /* Pick tags from next element */ | ||
1125 | if (tag_bit) | ||
1126 | iter->tags |= node->tags[tag][tag_long + 1] << | ||
1127 | (BITS_PER_LONG - tag_bit); | ||
1128 | /* Clip chunk size, here only BITS_PER_LONG tags */ | ||
1129 | iter->next_index = __radix_tree_iter_add(iter, BITS_PER_LONG); | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | #ifdef CONFIG_RADIX_TREE_MULTIORDER | ||
1134 | static void **skip_siblings(struct radix_tree_node **nodep, | ||
1135 | void **slot, struct radix_tree_iter *iter) | ||
1136 | { | ||
1137 | void *sib = node_to_entry(slot - 1); | ||
1138 | |||
1139 | while (iter->index < iter->next_index) { | ||
1140 | *nodep = rcu_dereference_raw(*slot); | ||
1141 | if (*nodep && *nodep != sib) | ||
1142 | return slot; | ||
1143 | slot++; | ||
1144 | iter->index = __radix_tree_iter_add(iter, 1); | ||
1145 | iter->tags >>= 1; | ||
1146 | } | ||
1147 | |||
1148 | *nodep = NULL; | ||
1149 | return NULL; | ||
1150 | } | ||
1151 | |||
1152 | void ** __radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, | ||
1153 | unsigned flags) | ||
1154 | { | ||
1155 | unsigned tag = flags & RADIX_TREE_ITER_TAG_MASK; | ||
1156 | struct radix_tree_node *node = rcu_dereference_raw(*slot); | ||
1157 | |||
1158 | slot = skip_siblings(&node, slot, iter); | ||
1159 | |||
1160 | while (radix_tree_is_internal_node(node)) { | ||
1161 | unsigned offset; | ||
1162 | unsigned long next_index; | ||
1163 | |||
1164 | if (node == RADIX_TREE_RETRY) | ||
1165 | return slot; | ||
1166 | node = entry_to_node(node); | ||
1167 | iter->shift = node->shift; | ||
1168 | |||
1169 | if (flags & RADIX_TREE_ITER_TAGGED) { | ||
1170 | offset = radix_tree_find_next_bit(node, tag, 0); | ||
1171 | if (offset == RADIX_TREE_MAP_SIZE) | ||
1172 | return NULL; | ||
1173 | slot = &node->slots[offset]; | ||
1174 | iter->index = __radix_tree_iter_add(iter, offset); | ||
1175 | set_iter_tags(iter, node, offset, tag); | ||
1176 | node = rcu_dereference_raw(*slot); | ||
1177 | } else { | ||
1178 | offset = 0; | ||
1179 | slot = &node->slots[0]; | ||
1180 | for (;;) { | ||
1181 | node = rcu_dereference_raw(*slot); | ||
1182 | if (node) | ||
1183 | break; | ||
1184 | slot++; | ||
1185 | offset++; | ||
1186 | if (offset == RADIX_TREE_MAP_SIZE) | ||
1187 | return NULL; | ||
1188 | } | ||
1189 | iter->index = __radix_tree_iter_add(iter, offset); | ||
1190 | } | ||
1191 | if ((flags & RADIX_TREE_ITER_CONTIG) && (offset > 0)) | ||
1192 | goto none; | ||
1193 | next_index = (iter->index | shift_maxindex(iter->shift)) + 1; | ||
1194 | if (next_index < iter->next_index) | ||
1195 | iter->next_index = next_index; | ||
1196 | } | ||
1197 | |||
1198 | return slot; | ||
1199 | none: | ||
1200 | iter->next_index = 0; | ||
1201 | return NULL; | ||
1202 | } | ||
1203 | EXPORT_SYMBOL(__radix_tree_next_slot); | ||
1204 | #else | ||
1205 | static void **skip_siblings(struct radix_tree_node **nodep, | ||
1206 | void **slot, struct radix_tree_iter *iter) | ||
1207 | { | ||
1208 | return slot; | ||
1209 | } | ||
1210 | #endif | ||
1211 | |||
1212 | void **radix_tree_iter_resume(void **slot, struct radix_tree_iter *iter) | ||
1213 | { | ||
1214 | struct radix_tree_node *node; | ||
1215 | |||
1216 | slot++; | ||
1217 | iter->index = __radix_tree_iter_add(iter, 1); | ||
1218 | node = rcu_dereference_raw(*slot); | ||
1219 | skip_siblings(&node, slot, iter); | ||
1220 | iter->next_index = iter->index; | ||
1221 | iter->tags = 0; | ||
1222 | return NULL; | ||
1223 | } | ||
1224 | EXPORT_SYMBOL(radix_tree_iter_resume); | ||
1225 | |||
1107 | /** | 1226 | /** |
1108 | * radix_tree_next_chunk - find next chunk of slots for iteration | 1227 | * radix_tree_next_chunk - find next chunk of slots for iteration |
1109 | * | 1228 | * |
@@ -1191,23 +1310,8 @@ void **radix_tree_next_chunk(struct radix_tree_root *root, | |||
1191 | iter->next_index = (index | node_maxindex(node)) + 1; | 1310 | iter->next_index = (index | node_maxindex(node)) + 1; |
1192 | __set_iter_shift(iter, node->shift); | 1311 | __set_iter_shift(iter, node->shift); |
1193 | 1312 | ||
1194 | /* Construct iter->tags bit-mask from node->tags[tag] array */ | 1313 | if (flags & RADIX_TREE_ITER_TAGGED) |
1195 | if (flags & RADIX_TREE_ITER_TAGGED) { | 1314 | set_iter_tags(iter, node, offset, tag); |
1196 | unsigned tag_long, tag_bit; | ||
1197 | |||
1198 | tag_long = offset / BITS_PER_LONG; | ||
1199 | tag_bit = offset % BITS_PER_LONG; | ||
1200 | iter->tags = node->tags[tag][tag_long] >> tag_bit; | ||
1201 | /* This never happens if RADIX_TREE_TAG_LONGS == 1 */ | ||
1202 | if (tag_long < RADIX_TREE_TAG_LONGS - 1) { | ||
1203 | /* Pick tags from next element */ | ||
1204 | if (tag_bit) | ||
1205 | iter->tags |= node->tags[tag][tag_long + 1] << | ||
1206 | (BITS_PER_LONG - tag_bit); | ||
1207 | /* Clip chunk size, here only BITS_PER_LONG tags */ | ||
1208 | iter->next_index = index + BITS_PER_LONG; | ||
1209 | } | ||
1210 | } | ||
1211 | 1315 | ||
1212 | return node->slots + offset; | 1316 | return node->slots + offset; |
1213 | } | 1317 | } |