// XA_BUG_ON(xa, xa_err(xa_store(xa, 0, xa_mk_internal(0), 0)) != -EINVAL);
}
-static noinline void check_xas_retry(struct xarray *xa)
+static noinline void check_xas_retry_1(struct xarray *xa)
{
XA_STATE(xas, xa, 0);
void *entry;
xa_erase_index(xa, 1);
}
+static noinline void check_xas_retry_2(struct xarray *xa)
+{
+ XA_STATE(xas, xa, 0);
+ void *entry;
+ bool first;
+
+ xa_store_index(xa, 0, GFP_KERNEL);
+ xa_set_mark(xa, 0, XA_MARK_0);
+
+ first = true;
+ rcu_read_lock();
+ xas_for_each_marked(&xas, entry, ULONG_MAX, XA_MARK_0) {
+ if (first) {
+ xa_store_index(xa, 1, GFP_KERNEL);
+ xa_set_mark(xa, 1, XA_MARK_0);
+ first = false;
+ }
+ if (xas_retry(&xas, entry))
+ continue;
+ }
+ rcu_read_unlock();
+ xa_erase_index(xa, 1);
+
+ first = true;
+ xas_set(&xas, 0);
+ rcu_read_lock();
+ xas_for_each(&xas, entry, ULONG_MAX) {
+ if (xas_retry(&xas, entry))
+ continue;
+ if (first) {
+ xa_store_index(xa, 1, GFP_KERNEL);
+ first = false;
+ }
+ }
+ rcu_read_unlock();
+
+ xas_set(&xas, 0);
+ rcu_read_lock();
+ xas_for_each(&xas, entry, ULONG_MAX) {
+ if (xas.xa_index == 0)
+ xas_pause(&xas);
+ }
+ rcu_read_unlock();
+
+ xa_set_mark(xa, 0, XA_MARK_0);
+ xa_set_mark(xa, 1, XA_MARK_0);
+ xas_set(&xas, 0);
+ rcu_read_lock();
+ xas_for_each_marked(&xas, entry, ULONG_MAX, XA_MARK_0) {
+ if (xas.xa_index == 0)
+ xas_pause(&xas);
+ }
+ rcu_read_unlock();
+
+ xa_erase_index(xa, 0);
+ xa_erase_index(xa, 1);
+}
+
+static noinline void check_xas_retry(struct xarray *xa)
+{
+ check_xas_retry_1(xa);
+ check_xas_retry_2(xa);
+}
+
static noinline void check_xa_load(struct xarray *xa)
{
unsigned long i, j;
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Regression3
- * Description:
- * Helper radix_tree_iter_retry resets next_index to the current index.
- * In following radix_tree_next_slot current chunk size becomes zero.
- * This isn't checked and it tries to dereference null pointer in slot.
- *
- * Helper radix_tree_iter_resume reset slot to NULL and next_index to index + 1,
- * for tagger iteraction it also must reset cached tags in iterator to abort
- * next radix_tree_next_slot and go to slow-path into radix_tree_next_chunk.
- *
- * Running:
- * This test should run to completion immediately. The above bug would
- * cause it to segfault.
- *
- * Upstream commit:
- * Not yet
- */
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-#include <linux/slab.h>
-#include <linux/radix-tree.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "regression.h"
-
-void regression3_test(void)
-{
- RADIX_TREE(root, GFP_KERNEL);
- void *ptr0 = (void *)4ul;
- void *ptr = (void *)8ul;
- struct radix_tree_iter iter;
- void **slot;
- bool first;
-
- printv(1, "running regression test 3 (should take milliseconds)\n");
-
- radix_tree_insert(&root, 0, ptr0);
- radix_tree_tag_set(&root, 0, 0);
-
- first = true;
- radix_tree_for_each_tagged(slot, &root, &iter, 0, 0) {
- printv(2, "tagged %ld %p\n", iter.index, *slot);
- if (first) {
- radix_tree_insert(&root, 1, ptr);
- radix_tree_tag_set(&root, 1, 0);
- first = false;
- }
- if (radix_tree_deref_retry(*slot)) {
- printv(2, "retry at %ld\n", iter.index);
- slot = radix_tree_iter_retry(&iter);
- continue;
- }
- }
- radix_tree_delete(&root, 1);
-
- first = true;
- radix_tree_for_each_slot(slot, &root, &iter, 0) {
- printv(2, "slot %ld %p\n", iter.index, *slot);
- if (first) {
- radix_tree_insert(&root, 1, ptr);
- first = false;
- }
- if (radix_tree_deref_retry(*slot)) {
- printv(2, "retry at %ld\n", iter.index);
- slot = radix_tree_iter_retry(&iter);
- continue;
- }
- }
-
- radix_tree_for_each_slot(slot, &root, &iter, 0) {
- printv(2, "slot %ld %p\n", iter.index, *slot);
- if (!iter.index) {
- printv(2, "next at %ld\n", iter.index);
- slot = radix_tree_iter_resume(slot, &iter);
- }
- }
-
- radix_tree_tag_set(&root, 0, 0);
- radix_tree_tag_set(&root, 1, 0);
- radix_tree_for_each_tagged(slot, &root, &iter, 0, 0) {
- printv(2, "tagged %ld %p\n", iter.index, *slot);
- if (!iter.index) {
- printv(2, "next at %ld\n", iter.index);
- slot = radix_tree_iter_resume(slot, &iter);
- }
- }
-
- radix_tree_delete(&root, 0);
- radix_tree_delete(&root, 1);
-
- printv(1, "regression test 3 passed\n");
-}