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>
This commit is contained in:
parent
30b888ba95
commit
0ac398ef39
|
@ -311,6 +311,8 @@ void __radix_tree_delete_node(struct radix_tree_root *root,
|
||||||
struct radix_tree_node *node,
|
struct radix_tree_node *node,
|
||||||
radix_tree_update_node_t update_node,
|
radix_tree_update_node_t update_node,
|
||||||
void *private);
|
void *private);
|
||||||
|
void radix_tree_iter_delete(struct radix_tree_root *,
|
||||||
|
struct radix_tree_iter *iter, void **slot);
|
||||||
void *radix_tree_delete_item(struct radix_tree_root *, unsigned long, void *);
|
void *radix_tree_delete_item(struct radix_tree_root *, unsigned long, void *);
|
||||||
void *radix_tree_delete(struct radix_tree_root *, unsigned long);
|
void *radix_tree_delete(struct radix_tree_root *, unsigned long);
|
||||||
void radix_tree_clear_tags(struct radix_tree_root *root,
|
void radix_tree_clear_tags(struct radix_tree_root *root,
|
||||||
|
|
|
@ -581,10 +581,12 @@ out:
|
||||||
* radix_tree_shrink - shrink radix tree to minimum height
|
* radix_tree_shrink - shrink radix tree to minimum height
|
||||||
* @root radix tree root
|
* @root radix tree root
|
||||||
*/
|
*/
|
||||||
static inline void radix_tree_shrink(struct radix_tree_root *root,
|
static inline bool radix_tree_shrink(struct radix_tree_root *root,
|
||||||
radix_tree_update_node_t update_node,
|
radix_tree_update_node_t update_node,
|
||||||
void *private)
|
void *private)
|
||||||
{
|
{
|
||||||
|
bool shrunk = false;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
struct radix_tree_node *node = root->rnode;
|
struct radix_tree_node *node = root->rnode;
|
||||||
struct radix_tree_node *child;
|
struct radix_tree_node *child;
|
||||||
|
@ -645,20 +647,26 @@ static inline void radix_tree_shrink(struct radix_tree_root *root,
|
||||||
|
|
||||||
WARN_ON_ONCE(!list_empty(&node->private_list));
|
WARN_ON_ONCE(!list_empty(&node->private_list));
|
||||||
radix_tree_node_free(node);
|
radix_tree_node_free(node);
|
||||||
|
shrunk = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return shrunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void delete_node(struct radix_tree_root *root,
|
static bool delete_node(struct radix_tree_root *root,
|
||||||
struct radix_tree_node *node,
|
struct radix_tree_node *node,
|
||||||
radix_tree_update_node_t update_node, void *private)
|
radix_tree_update_node_t update_node, void *private)
|
||||||
{
|
{
|
||||||
|
bool deleted = false;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
struct radix_tree_node *parent;
|
struct radix_tree_node *parent;
|
||||||
|
|
||||||
if (node->count) {
|
if (node->count) {
|
||||||
if (node == entry_to_node(root->rnode))
|
if (node == entry_to_node(root->rnode))
|
||||||
radix_tree_shrink(root, update_node, private);
|
deleted |= radix_tree_shrink(root, update_node,
|
||||||
return;
|
private);
|
||||||
|
return deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent = node->parent;
|
parent = node->parent;
|
||||||
|
@ -672,9 +680,12 @@ static void delete_node(struct radix_tree_root *root,
|
||||||
|
|
||||||
WARN_ON_ONCE(!list_empty(&node->private_list));
|
WARN_ON_ONCE(!list_empty(&node->private_list));
|
||||||
radix_tree_node_free(node);
|
radix_tree_node_free(node);
|
||||||
|
deleted = true;
|
||||||
|
|
||||||
node = parent;
|
node = parent;
|
||||||
} while (node);
|
} while (node);
|
||||||
|
|
||||||
|
return deleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1859,25 +1870,55 @@ void __radix_tree_delete_node(struct radix_tree_root *root,
|
||||||
delete_node(root, node, update_node, private);
|
delete_node(root, node, update_node, private);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool __radix_tree_delete(struct radix_tree_root *root,
|
||||||
|
struct radix_tree_node *node, void **slot)
|
||||||
|
{
|
||||||
|
unsigned offset = get_slot_offset(node, slot);
|
||||||
|
int tag;
|
||||||
|
|
||||||
|
for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++)
|
||||||
|
node_tag_clear(root, node, tag, offset);
|
||||||
|
|
||||||
|
replace_slot(root, node, slot, NULL, true);
|
||||||
|
return node && delete_node(root, node, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* radix_tree_delete_item - delete an item from a radix tree
|
* radix_tree_iter_delete - delete the entry at this iterator position
|
||||||
* @root: radix tree root
|
* @root: radix tree root
|
||||||
* @index: index key
|
* @iter: iterator state
|
||||||
* @item: expected item
|
* @slot: pointer to slot
|
||||||
*
|
*
|
||||||
* Remove @item at @index from the radix tree rooted at @root.
|
* Delete the entry at the position currently pointed to by the iterator.
|
||||||
|
* This may result in the current node being freed; if it is, the iterator
|
||||||
|
* is advanced so that it will not reference the freed memory. This
|
||||||
|
* function may be called without any locking if there are no other threads
|
||||||
|
* which can access this tree.
|
||||||
|
*/
|
||||||
|
void radix_tree_iter_delete(struct radix_tree_root *root,
|
||||||
|
struct radix_tree_iter *iter, void **slot)
|
||||||
|
{
|
||||||
|
if (__radix_tree_delete(root, iter->node, slot))
|
||||||
|
iter->index = iter->next_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* radix_tree_delete_item - delete an item from a radix tree
|
||||||
|
* @root: radix tree root
|
||||||
|
* @index: index key
|
||||||
|
* @item: expected item
|
||||||
*
|
*
|
||||||
* Returns the address of the deleted item, or NULL if it was not present
|
* Remove @item at @index from the radix tree rooted at @root.
|
||||||
* or the entry at the given @index was not @item.
|
*
|
||||||
|
* Return: the deleted entry, or %NULL if it was not present
|
||||||
|
* or the entry at the given @index was not @item.
|
||||||
*/
|
*/
|
||||||
void *radix_tree_delete_item(struct radix_tree_root *root,
|
void *radix_tree_delete_item(struct radix_tree_root *root,
|
||||||
unsigned long index, void *item)
|
unsigned long index, void *item)
|
||||||
{
|
{
|
||||||
struct radix_tree_node *node;
|
struct radix_tree_node *node;
|
||||||
unsigned int offset;
|
|
||||||
void **slot;
|
void **slot;
|
||||||
void *entry;
|
void *entry;
|
||||||
int tag;
|
|
||||||
|
|
||||||
entry = __radix_tree_lookup(root, index, &node, &slot);
|
entry = __radix_tree_lookup(root, index, &node, &slot);
|
||||||
if (!entry)
|
if (!entry)
|
||||||
|
@ -1886,32 +1927,20 @@ void *radix_tree_delete_item(struct radix_tree_root *root,
|
||||||
if (item && entry != item)
|
if (item && entry != item)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!node) {
|
__radix_tree_delete(root, node, slot);
|
||||||
root_tag_clear_all(root);
|
|
||||||
root->rnode = NULL;
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = get_slot_offset(node, slot);
|
|
||||||
|
|
||||||
/* Clear all tags associated with the item to be deleted. */
|
|
||||||
for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++)
|
|
||||||
node_tag_clear(root, node, tag, offset);
|
|
||||||
|
|
||||||
__radix_tree_replace(root, node, slot, NULL, NULL, NULL);
|
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(radix_tree_delete_item);
|
EXPORT_SYMBOL(radix_tree_delete_item);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* radix_tree_delete - delete an item from a radix tree
|
* radix_tree_delete - delete an entry from a radix tree
|
||||||
* @root: radix tree root
|
* @root: radix tree root
|
||||||
* @index: index key
|
* @index: index key
|
||||||
*
|
*
|
||||||
* Remove the item at @index from the radix tree rooted at @root.
|
* Remove the entry at @index from the radix tree rooted at @root.
|
||||||
*
|
*
|
||||||
* Returns the address of the deleted item, or NULL if it was not present.
|
* Return: The deleted entry, or %NULL if it was not present.
|
||||||
*/
|
*/
|
||||||
void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
|
void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue