aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Wilcox <mawilcox@microsoft.com>2017-01-28 09:56:22 -0500
committerMatthew Wilcox <mawilcox@microsoft.com>2017-02-13 16:09:55 -0500
commit0ac398ef391b53122976325ab6953456ce8e8310 (patch)
tree99318e48860947c93bb7a230e66834abd67bef7a
parent30b888ba950d9f77326b50a4aa2d7d99557d5718 (diff)
radix-tree: Add radix_tree_iter_delete
Factor the deletion code out into __radix_tree_delete() and provide a nice iterator-based wrapper around it. If we free the node, advance the iterator to avoid reading from freed memory. Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com>
-rw-r--r--include/linux/radix-tree.h2
-rw-r--r--lib/radix-tree.c91
2 files changed, 62 insertions, 31 deletions
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index 8bf4ef448ce1..05f715cb8062 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -311,6 +311,8 @@ void __radix_tree_delete_node(struct radix_tree_root *root,
311 struct radix_tree_node *node, 311 struct radix_tree_node *node,
312 radix_tree_update_node_t update_node, 312 radix_tree_update_node_t update_node,
313 void *private); 313 void *private);
314void radix_tree_iter_delete(struct radix_tree_root *,
315 struct radix_tree_iter *iter, void **slot);
314void *radix_tree_delete_item(struct radix_tree_root *, unsigned long, void *); 316void *radix_tree_delete_item(struct radix_tree_root *, unsigned long, void *);
315void *radix_tree_delete(struct radix_tree_root *, unsigned long); 317void *radix_tree_delete(struct radix_tree_root *, unsigned long);
316void radix_tree_clear_tags(struct radix_tree_root *root, 318void radix_tree_clear_tags(struct radix_tree_root *root,
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 40f3091c5a6b..7bf7d4e60e43 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -581,10 +581,12 @@ out:
581 * radix_tree_shrink - shrink radix tree to minimum height 581 * radix_tree_shrink - shrink radix tree to minimum height
582 * @root radix tree root 582 * @root radix tree root
583 */ 583 */
584static inline void radix_tree_shrink(struct radix_tree_root *root, 584static inline bool radix_tree_shrink(struct radix_tree_root *root,
585 radix_tree_update_node_t update_node, 585 radix_tree_update_node_t update_node,
586 void *private) 586 void *private)
587{ 587{
588 bool shrunk = false;
589
588 for (;;) { 590 for (;;) {
589 struct radix_tree_node *node = root->rnode; 591 struct radix_tree_node *node = root->rnode;
590 struct radix_tree_node *child; 592 struct radix_tree_node *child;
@@ -645,20 +647,26 @@ static inline void radix_tree_shrink(struct radix_tree_root *root,
645 647
646 WARN_ON_ONCE(!list_empty(&node->private_list)); 648 WARN_ON_ONCE(!list_empty(&node->private_list));
647 radix_tree_node_free(node); 649 radix_tree_node_free(node);
650 shrunk = true;
648 } 651 }
652
653 return shrunk;
649} 654}
650 655
651static void delete_node(struct radix_tree_root *root, 656static bool delete_node(struct radix_tree_root *root,
652 struct radix_tree_node *node, 657 struct radix_tree_node *node,
653 radix_tree_update_node_t update_node, void *private) 658 radix_tree_update_node_t update_node, void *private)
654{ 659{
660 bool deleted = false;
661
655 do { 662 do {
656 struct radix_tree_node *parent; 663 struct radix_tree_node *parent;
657 664
658 if (node->count) { 665 if (node->count) {
659 if (node == entry_to_node(root->rnode)) 666 if (node == entry_to_node(root->rnode))
660 radix_tree_shrink(root, update_node, private); 667 deleted |= radix_tree_shrink(root, update_node,
661 return; 668 private);
669 return deleted;
662 } 670 }
663 671
664 parent = node->parent; 672 parent = node->parent;
@@ -672,9 +680,12 @@ static void delete_node(struct radix_tree_root *root,
672 680
673 WARN_ON_ONCE(!list_empty(&node->private_list)); 681 WARN_ON_ONCE(!list_empty(&node->private_list));
674 radix_tree_node_free(node); 682 radix_tree_node_free(node);
683 deleted = true;
675 684
676 node = parent; 685 node = parent;
677 } while (node); 686 } while (node);
687
688 return deleted;
678} 689}
679 690
680/** 691/**
@@ -1859,25 +1870,55 @@ void __radix_tree_delete_node(struct radix_tree_root *root,
1859 delete_node(root, node, update_node, private); 1870 delete_node(root, node, update_node, private);
1860} 1871}
1861 1872
1873static bool __radix_tree_delete(struct radix_tree_root *root,
1874 struct radix_tree_node *node, void **slot)
1875{
1876 unsigned offset = get_slot_offset(node, slot);
1877 int tag;
1878
1879 for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++)
1880 node_tag_clear(root, node, tag, offset);
1881
1882 replace_slot(root, node, slot, NULL, true);
1883 return node && delete_node(root, node, NULL, NULL);
1884}
1885
1862/** 1886/**
1863 * radix_tree_delete_item - delete an item from a radix tree 1887 * radix_tree_iter_delete - delete the entry at this iterator position
1864 * @root: radix tree root 1888 * @root: radix tree root
1865 * @index: index key 1889 * @iter: iterator state
1866 * @item: expected item 1890 * @slot: pointer to slot
1867 * 1891 *
1868 * Remove @item at @index from the radix tree rooted at @root. 1892 * Delete the entry at the position currently pointed to by the iterator.
1893 * This may result in the current node being freed; if it is, the iterator
1894 * is advanced so that it will not reference the freed memory. This
1895 * function may be called without any locking if there are no other threads
1896 * which can access this tree.
1897 */
1898void radix_tree_iter_delete(struct radix_tree_root *root,
1899 struct radix_tree_iter *iter, void **slot)
1900{
1901 if (__radix_tree_delete(root, iter->node, slot))
1902 iter->index = iter->next_index;
1903}
1904
1905/**
1906 * radix_tree_delete_item - delete an item from a radix tree
1907 * @root: radix tree root
1908 * @index: index key
1909 * @item: expected item
1910 *
1911 * Remove @item at @index from the radix tree rooted at @root.
1869 * 1912 *
1870 * Returns the address of the deleted item, or NULL if it was not present 1913 * Return: the deleted entry, or %NULL if it was not present
1871 * or the entry at the given @index was not @item. 1914 * or the entry at the given @index was not @item.
1872 */ 1915 */
1873void *radix_tree_delete_item(struct radix_tree_root *root, 1916void *radix_tree_delete_item(struct radix_tree_root *root,
1874 unsigned long index, void *item) 1917 unsigned long index, void *item)
1875{ 1918{
1876 struct radix_tree_node *node; 1919 struct radix_tree_node *node;
1877 unsigned int offset;
1878 void **slot; 1920 void **slot;
1879 void *entry; 1921 void *entry;
1880 int tag;
1881 1922
1882 entry = __radix_tree_lookup(root, index, &node, &slot); 1923 entry = __radix_tree_lookup(root, index, &node, &slot);
1883 if (!entry) 1924 if (!entry)
@@ -1886,32 +1927,20 @@ void *radix_tree_delete_item(struct radix_tree_root *root,
1886 if (item && entry != item) 1927 if (item && entry != item)
1887 return NULL; 1928 return NULL;
1888 1929
1889 if (!node) { 1930 __radix_tree_delete(root, node, slot);
1890 root_tag_clear_all(root);
1891 root->rnode = NULL;
1892 return entry;
1893 }
1894
1895 offset = get_slot_offset(node, slot);
1896
1897 /* Clear all tags associated with the item to be deleted. */
1898 for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++)
1899 node_tag_clear(root, node, tag, offset);
1900
1901 __radix_tree_replace(root, node, slot, NULL, NULL, NULL);
1902 1931
1903 return entry; 1932 return entry;
1904} 1933}
1905EXPORT_SYMBOL(radix_tree_delete_item); 1934EXPORT_SYMBOL(radix_tree_delete_item);
1906 1935
1907/** 1936/**
1908 * radix_tree_delete - delete an item from a radix tree 1937 * radix_tree_delete - delete an entry from a radix tree
1909 * @root: radix tree root 1938 * @root: radix tree root
1910 * @index: index key 1939 * @index: index key
1911 * 1940 *
1912 * Remove the item at @index from the radix tree rooted at @root. 1941 * Remove the entry at @index from the radix tree rooted at @root.
1913 * 1942 *
1914 * Returns the address of the deleted item, or NULL if it was not present. 1943 * Return: The deleted entry, or %NULL if it was not present.
1915 */ 1944 */
1916void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) 1945void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
1917{ 1946{