Path: blob/master/tools/testing/radix-tree/iteration_check.c
26285 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* iteration_check.c: test races having to do with xarray iteration3* Copyright (c) 2016 Intel Corporation4* Author: Ross Zwisler <[email protected]>5*/6#include <pthread.h>7#include "test.h"89#define NUM_THREADS 510#define MAX_IDX 10011#define TAG XA_MARK_012#define NEW_TAG XA_MARK_11314static pthread_t threads[NUM_THREADS];15static unsigned int seeds[3];16static DEFINE_XARRAY(array);17static bool test_complete;18static int max_order;1920void my_item_insert(struct xarray *xa, unsigned long index)21{22XA_STATE(xas, xa, index);23struct item *item = item_create(index, 0);24int order;2526retry:27xas_lock(&xas);28for (order = max_order; order >= 0; order--) {29xas_set_order(&xas, index, order);30item->order = order;31if (xas_find_conflict(&xas))32continue;33xas_store(&xas, item);34xas_set_mark(&xas, TAG);35break;36}37xas_unlock(&xas);38if (xas_nomem(&xas, GFP_KERNEL))39goto retry;40if (order < 0)41free(item);42}4344/* relentlessly fill the array with tagged entries */45static void *add_entries_fn(void *arg)46{47rcu_register_thread();4849while (!test_complete) {50unsigned long pgoff;5152for (pgoff = 0; pgoff < MAX_IDX; pgoff++) {53my_item_insert(&array, pgoff);54}55}5657rcu_unregister_thread();5859return NULL;60}6162/*63* Iterate over tagged entries, retrying when we find ourselves in a deleted64* node and randomly pausing the iteration.65*/66static void *tagged_iteration_fn(void *arg)67{68XA_STATE(xas, &array, 0);69void *entry;7071rcu_register_thread();7273while (!test_complete) {74xas_set(&xas, 0);75rcu_read_lock();76xas_for_each_marked(&xas, entry, ULONG_MAX, TAG) {77if (xas_retry(&xas, entry))78continue;7980if (rand_r(&seeds[0]) % 50 == 0) {81xas_pause(&xas);82rcu_read_unlock();83rcu_barrier();84rcu_read_lock();85}86}87rcu_read_unlock();88}8990rcu_unregister_thread();9192return NULL;93}9495/*96* Iterate over the entries, retrying when we find ourselves in a deleted97* node and randomly pausing the iteration.98*/99static void *untagged_iteration_fn(void *arg)100{101XA_STATE(xas, &array, 0);102void *entry;103104rcu_register_thread();105106while (!test_complete) {107xas_set(&xas, 0);108rcu_read_lock();109xas_for_each(&xas, entry, ULONG_MAX) {110if (xas_retry(&xas, entry))111continue;112113if (rand_r(&seeds[1]) % 50 == 0) {114xas_pause(&xas);115rcu_read_unlock();116rcu_barrier();117rcu_read_lock();118}119}120rcu_read_unlock();121}122123rcu_unregister_thread();124125return NULL;126}127128/*129* Randomly remove entries to help induce retries in the130* two iteration functions.131*/132static void *remove_entries_fn(void *arg)133{134rcu_register_thread();135136while (!test_complete) {137int pgoff;138struct item *item;139140pgoff = rand_r(&seeds[2]) % MAX_IDX;141142item = xa_erase(&array, pgoff);143if (item)144item_free(item, pgoff);145}146147rcu_unregister_thread();148149return NULL;150}151152static void *tag_entries_fn(void *arg)153{154rcu_register_thread();155156while (!test_complete) {157tag_tagged_items(&array, 0, MAX_IDX, 10, TAG, NEW_TAG);158}159rcu_unregister_thread();160return NULL;161}162163/* This is a unit test for a bug found by the syzkaller tester */164void iteration_test(unsigned order, unsigned test_duration)165{166int i;167168printv(1, "Running %siteration tests for %d seconds\n",169order > 0 ? "multiorder " : "", test_duration);170171max_order = order;172test_complete = false;173174for (i = 0; i < 3; i++)175seeds[i] = rand();176177if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) {178perror("create tagged iteration thread");179exit(1);180}181if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) {182perror("create untagged iteration thread");183exit(1);184}185if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) {186perror("create add entry thread");187exit(1);188}189if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) {190perror("create remove entry thread");191exit(1);192}193if (pthread_create(&threads[4], NULL, tag_entries_fn, NULL)) {194perror("create tag entry thread");195exit(1);196}197198sleep(test_duration);199test_complete = true;200201for (i = 0; i < NUM_THREADS; i++) {202if (pthread_join(threads[i], NULL)) {203perror("pthread_join");204exit(1);205}206}207208item_kill_tree(&array);209}210211212