Skip to content

Commit 47feff2

Browse files
Nick Piggintorvalds
authored andcommitted
radix-tree: add gang_lookup_slot, gang_lookup_slot_tag
Introduce gang_lookup_slot() and gang_lookup_slot_tag() functions, which are used by lockless pagecache. Signed-off-by: Nick Piggin <[email protected]> Cc: Benjamin Herrenschmidt <[email protected]> Cc: Paul Mackerras <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: "Paul E. McKenney" <[email protected]> Reviewed-by: Peter Zijlstra <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 30002ed commit 47feff2

File tree

2 files changed

+166
-24
lines changed

2 files changed

+166
-24
lines changed

include/linux/radix-tree.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,15 @@ do { \
9999
*
100100
* The notable exceptions to this rule are the following functions:
101101
* radix_tree_lookup
102+
* radix_tree_lookup_slot
102103
* radix_tree_tag_get
103104
* radix_tree_gang_lookup
105+
* radix_tree_gang_lookup_slot
104106
* radix_tree_gang_lookup_tag
107+
* radix_tree_gang_lookup_tag_slot
105108
* radix_tree_tagged
106109
*
107-
* The first 4 functions are able to be called locklessly, using RCU. The
110+
* The first 7 functions are able to be called locklessly, using RCU. The
108111
* caller must ensure calls to these functions are made within rcu_read_lock()
109112
* regions. Other readers (lock-free or otherwise) and modifications may be
110113
* running concurrently.
@@ -159,6 +162,9 @@ void *radix_tree_delete(struct radix_tree_root *, unsigned long);
159162
unsigned int
160163
radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
161164
unsigned long first_index, unsigned int max_items);
165+
unsigned int
166+
radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results,
167+
unsigned long first_index, unsigned int max_items);
162168
unsigned long radix_tree_next_hole(struct radix_tree_root *root,
163169
unsigned long index, unsigned long max_scan);
164170
int radix_tree_preload(gfp_t gfp_mask);
@@ -173,6 +179,10 @@ unsigned int
173179
radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
174180
unsigned long first_index, unsigned int max_items,
175181
unsigned int tag);
182+
unsigned int
183+
radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results,
184+
unsigned long first_index, unsigned int max_items,
185+
unsigned int tag);
176186
int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag);
177187

178188
static inline void radix_tree_preload_end(void)

lib/radix-tree.c

Lines changed: 155 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -359,18 +359,17 @@ EXPORT_SYMBOL(radix_tree_insert);
359359
* Returns: the slot corresponding to the position @index in the
360360
* radix tree @root. This is useful for update-if-exists operations.
361361
*
362-
* This function cannot be called under rcu_read_lock, it must be
363-
* excluded from writers, as must the returned slot for subsequent
364-
* use by radix_tree_deref_slot() and radix_tree_replace slot.
365-
* Caller must hold tree write locked across slot lookup and
366-
* replace.
362+
* This function can be called under rcu_read_lock iff the slot is not
363+
* modified by radix_tree_replace_slot, otherwise it must be called
364+
* exclusive from other writers. Any dereference of the slot must be done
365+
* using radix_tree_deref_slot.
367366
*/
368367
void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
369368
{
370369
unsigned int height, shift;
371370
struct radix_tree_node *node, **slot;
372371

373-
node = root->rnode;
372+
node = rcu_dereference(root->rnode);
374373
if (node == NULL)
375374
return NULL;
376375

@@ -390,7 +389,7 @@ void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index)
390389
do {
391390
slot = (struct radix_tree_node **)
392391
(node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK));
393-
node = *slot;
392+
node = rcu_dereference(*slot);
394393
if (node == NULL)
395394
return NULL;
396395

@@ -667,7 +666,7 @@ unsigned long radix_tree_next_hole(struct radix_tree_root *root,
667666
EXPORT_SYMBOL(radix_tree_next_hole);
668667

669668
static unsigned int
670-
__lookup(struct radix_tree_node *slot, void **results, unsigned long index,
669+
__lookup(struct radix_tree_node *slot, void ***results, unsigned long index,
671670
unsigned int max_items, unsigned long *next_index)
672671
{
673672
unsigned int nr_found = 0;
@@ -701,11 +700,9 @@ __lookup(struct radix_tree_node *slot, void **results, unsigned long index,
701700

702701
/* Bottom level: grab some items */
703702
for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) {
704-
struct radix_tree_node *node;
705703
index++;
706-
node = slot->slots[i];
707-
if (node) {
708-
results[nr_found++] = rcu_dereference(node);
704+
if (slot->slots[i]) {
705+
results[nr_found++] = &(slot->slots[i]);
709706
if (nr_found == max_items)
710707
goto out;
711708
}
@@ -759,13 +756,22 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
759756

760757
ret = 0;
761758
while (ret < max_items) {
762-
unsigned int nr_found;
759+
unsigned int nr_found, slots_found, i;
763760
unsigned long next_index; /* Index of next search */
764761

765762
if (cur_index > max_index)
766763
break;
767-
nr_found = __lookup(node, results + ret, cur_index,
764+
slots_found = __lookup(node, (void ***)results + ret, cur_index,
768765
max_items - ret, &next_index);
766+
nr_found = 0;
767+
for (i = 0; i < slots_found; i++) {
768+
struct radix_tree_node *slot;
769+
slot = *(((void ***)results)[ret + i]);
770+
if (!slot)
771+
continue;
772+
results[ret + nr_found] = rcu_dereference(slot);
773+
nr_found++;
774+
}
769775
ret += nr_found;
770776
if (next_index == 0)
771777
break;
@@ -776,12 +782,71 @@ radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
776782
}
777783
EXPORT_SYMBOL(radix_tree_gang_lookup);
778784

785+
/**
786+
* radix_tree_gang_lookup_slot - perform multiple slot lookup on radix tree
787+
* @root: radix tree root
788+
* @results: where the results of the lookup are placed
789+
* @first_index: start the lookup from this key
790+
* @max_items: place up to this many items at *results
791+
*
792+
* Performs an index-ascending scan of the tree for present items. Places
793+
* their slots at *@results and returns the number of items which were
794+
* placed at *@results.
795+
*
796+
* The implementation is naive.
797+
*
798+
* Like radix_tree_gang_lookup as far as RCU and locking goes. Slots must
799+
* be dereferenced with radix_tree_deref_slot, and if using only RCU
800+
* protection, radix_tree_deref_slot may fail requiring a retry.
801+
*/
802+
unsigned int
803+
radix_tree_gang_lookup_slot(struct radix_tree_root *root, void ***results,
804+
unsigned long first_index, unsigned int max_items)
805+
{
806+
unsigned long max_index;
807+
struct radix_tree_node *node;
808+
unsigned long cur_index = first_index;
809+
unsigned int ret;
810+
811+
node = rcu_dereference(root->rnode);
812+
if (!node)
813+
return 0;
814+
815+
if (!radix_tree_is_indirect_ptr(node)) {
816+
if (first_index > 0)
817+
return 0;
818+
results[0] = (void **)&root->rnode;
819+
return 1;
820+
}
821+
node = radix_tree_indirect_to_ptr(node);
822+
823+
max_index = radix_tree_maxindex(node->height);
824+
825+
ret = 0;
826+
while (ret < max_items) {
827+
unsigned int slots_found;
828+
unsigned long next_index; /* Index of next search */
829+
830+
if (cur_index > max_index)
831+
break;
832+
slots_found = __lookup(node, results + ret, cur_index,
833+
max_items - ret, &next_index);
834+
ret += slots_found;
835+
if (next_index == 0)
836+
break;
837+
cur_index = next_index;
838+
}
839+
840+
return ret;
841+
}
842+
EXPORT_SYMBOL(radix_tree_gang_lookup_slot);
843+
779844
/*
780845
* FIXME: the two tag_get()s here should use find_next_bit() instead of
781846
* open-coding the search.
782847
*/
783848
static unsigned int
784-
__lookup_tag(struct radix_tree_node *slot, void **results, unsigned long index,
849+
__lookup_tag(struct radix_tree_node *slot, void ***results, unsigned long index,
785850
unsigned int max_items, unsigned long *next_index, unsigned int tag)
786851
{
787852
unsigned int nr_found = 0;
@@ -811,11 +876,9 @@ __lookup_tag(struct radix_tree_node *slot, void **results, unsigned long index,
811876
unsigned long j = index & RADIX_TREE_MAP_MASK;
812877

813878
for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
814-
struct radix_tree_node *node;
815879
index++;
816880
if (!tag_get(slot, tag, j))
817881
continue;
818-
node = slot->slots[j];
819882
/*
820883
* Even though the tag was found set, we need to
821884
* recheck that we have a non-NULL node, because
@@ -826,9 +889,8 @@ __lookup_tag(struct radix_tree_node *slot, void **results, unsigned long index,
826889
* lookup ->slots[x] without a lock (ie. can't
827890
* rely on its value remaining the same).
828891
*/
829-
if (node) {
830-
node = rcu_dereference(node);
831-
results[nr_found++] = node;
892+
if (slot->slots[j]) {
893+
results[nr_found++] = &(slot->slots[j]);
832894
if (nr_found == max_items)
833895
goto out;
834896
}
@@ -887,13 +949,22 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
887949

888950
ret = 0;
889951
while (ret < max_items) {
890-
unsigned int nr_found;
952+
unsigned int nr_found, slots_found, i;
891953
unsigned long next_index; /* Index of next search */
892954

893955
if (cur_index > max_index)
894956
break;
895-
nr_found = __lookup_tag(node, results + ret, cur_index,
896-
max_items - ret, &next_index, tag);
957+
slots_found = __lookup_tag(node, (void ***)results + ret,
958+
cur_index, max_items - ret, &next_index, tag);
959+
nr_found = 0;
960+
for (i = 0; i < slots_found; i++) {
961+
struct radix_tree_node *slot;
962+
slot = *(((void ***)results)[ret + i]);
963+
if (!slot)
964+
continue;
965+
results[ret + nr_found] = rcu_dereference(slot);
966+
nr_found++;
967+
}
897968
ret += nr_found;
898969
if (next_index == 0)
899970
break;
@@ -904,6 +975,67 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
904975
}
905976
EXPORT_SYMBOL(radix_tree_gang_lookup_tag);
906977

978+
/**
979+
* radix_tree_gang_lookup_tag_slot - perform multiple slot lookup on a
980+
* radix tree based on a tag
981+
* @root: radix tree root
982+
* @results: where the results of the lookup are placed
983+
* @first_index: start the lookup from this key
984+
* @max_items: place up to this many items at *results
985+
* @tag: the tag index (< RADIX_TREE_MAX_TAGS)
986+
*
987+
* Performs an index-ascending scan of the tree for present items which
988+
* have the tag indexed by @tag set. Places the slots at *@results and
989+
* returns the number of slots which were placed at *@results.
990+
*/
991+
unsigned int
992+
radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results,
993+
unsigned long first_index, unsigned int max_items,
994+
unsigned int tag)
995+
{
996+
struct radix_tree_node *node;
997+
unsigned long max_index;
998+
unsigned long cur_index = first_index;
999+
unsigned int ret;
1000+
1001+
/* check the root's tag bit */
1002+
if (!root_tag_get(root, tag))
1003+
return 0;
1004+
1005+
node = rcu_dereference(root->rnode);
1006+
if (!node)
1007+
return 0;
1008+
1009+
if (!radix_tree_is_indirect_ptr(node)) {
1010+
if (first_index > 0)
1011+
return 0;
1012+
results[0] = (void **)&root->rnode;
1013+
return 1;
1014+
}
1015+
node = radix_tree_indirect_to_ptr(node);
1016+
1017+
max_index = radix_tree_maxindex(node->height);
1018+
1019+
ret = 0;
1020+
while (ret < max_items) {
1021+
unsigned int slots_found;
1022+
unsigned long next_index; /* Index of next search */
1023+
1024+
if (cur_index > max_index)
1025+
break;
1026+
slots_found = __lookup_tag(node, results + ret,
1027+
cur_index, max_items - ret, &next_index, tag);
1028+
ret += slots_found;
1029+
if (next_index == 0)
1030+
break;
1031+
cur_index = next_index;
1032+
}
1033+
1034+
return ret;
1035+
}
1036+
EXPORT_SYMBOL(radix_tree_gang_lookup_tag_slot);
1037+
1038+
9071039
/**
9081040
* radix_tree_shrink - shrink height of a radix tree to minimal
9091041
* @root radix tree root

0 commit comments

Comments
 (0)