]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - lib/radix-tree.c
lib: radix-tree: check accounting of existing slot replacement users
[karo-tx-linux.git] / lib / radix-tree.c
index 7885796d35ae74bb615b567f2b1b0bae87562500..f91d5b0af654291bc559c64841da15e9066c6840 100644 (file)
@@ -753,19 +753,10 @@ void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
 }
 EXPORT_SYMBOL(radix_tree_lookup);
 
-/**
- * __radix_tree_replace                - replace item in a slot
- * @root:      radix tree root
- * @node:      pointer to tree node
- * @slot:      pointer to slot in @node
- * @item:      new item to store in the slot.
- *
- * For use with __radix_tree_lookup().  Caller must hold tree write locked
- * across slot lookup and replacement.
- */
-void __radix_tree_replace(struct radix_tree_root *root,
-                         struct radix_tree_node *node,
-                         void **slot, void *item)
+static void replace_slot(struct radix_tree_root *root,
+                        struct radix_tree_node *node,
+                        void **slot, void *item,
+                        bool warn_typeswitch)
 {
        void *old = rcu_dereference_raw(*slot);
        int exceptional;
@@ -776,7 +767,7 @@ void __radix_tree_replace(struct radix_tree_root *root,
        exceptional = !!radix_tree_exceptional_entry(item) -
                      !!radix_tree_exceptional_entry(old);
 
-       WARN_ON_ONCE(exceptional && !node && slot != (void **)&root->rnode);
+       WARN_ON_ONCE(warn_typeswitch && exceptional);
 
        if (node)
                node->exceptional += exceptional;
@@ -784,6 +775,50 @@ void __radix_tree_replace(struct radix_tree_root *root,
        rcu_assign_pointer(*slot, item);
 }
 
+/**
+ * __radix_tree_replace                - replace item in a slot
+ * @root:      radix tree root
+ * @node:      pointer to tree node
+ * @slot:      pointer to slot in @node
+ * @item:      new item to store in the slot.
+ *
+ * For use with __radix_tree_lookup().  Caller must hold tree write locked
+ * across slot lookup and replacement.
+ */
+void __radix_tree_replace(struct radix_tree_root *root,
+                         struct radix_tree_node *node,
+                         void **slot, void *item)
+{
+       /*
+        * This function supports replacing exceptional entries, but
+        * that needs accounting against the node unless the slot is
+        * root->rnode.
+        */
+       replace_slot(root, node, slot, item,
+                    !node && slot != (void **)&root->rnode);
+}
+
+/**
+ * radix_tree_replace_slot     - replace item in a slot
+ * @root:      radix tree root
+ * @slot:      pointer to slot
+ * @item:      new item to store in the slot.
+ *
+ * For use with radix_tree_lookup_slot(), radix_tree_gang_lookup_slot(),
+ * radix_tree_gang_lookup_tag_slot().  Caller must hold tree write locked
+ * across slot lookup and replacement.
+ *
+ * NOTE: This cannot be used to switch between non-entries (empty slots),
+ * regular entries, and exceptional entries, as that requires accounting
+ * inside the radix tree node. When switching from one type of entry to
+ * another, use __radix_tree_lookup() and __radix_tree_replace().
+ */
+void radix_tree_replace_slot(struct radix_tree_root *root,
+                            void **slot, void *item)
+{
+       replace_slot(root, NULL, slot, item, true);
+}
+
 /**
  *     radix_tree_tag_set - set a tag on a radix tree node
  *     @root:          radix tree root