Linux Audio

Check our new training course

Loading...
v6.2
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * iteration_check.c: test races having to do with xarray iteration
  4 * Copyright (c) 2016 Intel Corporation
  5 * Author: Ross Zwisler <ross.zwisler@linux.intel.com>
  6 */
  7#include <pthread.h>
  8#include "test.h"
  9
 10#define NUM_THREADS	5
 11#define MAX_IDX		100
 12#define TAG		XA_MARK_0
 13#define NEW_TAG		XA_MARK_1
 14
 15static pthread_t threads[NUM_THREADS];
 16static unsigned int seeds[3];
 17static DEFINE_XARRAY(array);
 18static bool test_complete;
 19static int max_order;
 20
 21void my_item_insert(struct xarray *xa, unsigned long index)
 22{
 23	XA_STATE(xas, xa, index);
 24	struct item *item = item_create(index, 0);
 25	int order;
 26
 27retry:
 28	xas_lock(&xas);
 29	for (order = max_order; order >= 0; order--) {
 30		xas_set_order(&xas, index, order);
 31		item->order = order;
 32		if (xas_find_conflict(&xas))
 33			continue;
 34		xas_store(&xas, item);
 35		xas_set_mark(&xas, TAG);
 36		break;
 37	}
 38	xas_unlock(&xas);
 39	if (xas_nomem(&xas, GFP_KERNEL))
 40		goto retry;
 41	if (order < 0)
 42		free(item);
 43}
 44
 45/* relentlessly fill the array with tagged entries */
 46static void *add_entries_fn(void *arg)
 47{
 48	rcu_register_thread();
 49
 50	while (!test_complete) {
 51		unsigned long pgoff;
 52
 53		for (pgoff = 0; pgoff < MAX_IDX; pgoff++) {
 54			my_item_insert(&array, pgoff);
 55		}
 56	}
 57
 58	rcu_unregister_thread();
 59
 60	return NULL;
 61}
 62
 63/*
 64 * Iterate over tagged entries, retrying when we find ourselves in a deleted
 65 * node and randomly pausing the iteration.
 66 */
 67static void *tagged_iteration_fn(void *arg)
 68{
 69	XA_STATE(xas, &array, 0);
 70	void *entry;
 71
 72	rcu_register_thread();
 73
 74	while (!test_complete) {
 75		xas_set(&xas, 0);
 76		rcu_read_lock();
 77		xas_for_each_marked(&xas, entry, ULONG_MAX, TAG) {
 78			if (xas_retry(&xas, entry))
 79				continue;
 80
 81			if (rand_r(&seeds[0]) % 50 == 0) {
 82				xas_pause(&xas);
 83				rcu_read_unlock();
 84				rcu_barrier();
 85				rcu_read_lock();
 86			}
 87		}
 88		rcu_read_unlock();
 89	}
 90
 91	rcu_unregister_thread();
 92
 93	return NULL;
 94}
 95
 96/*
 97 * Iterate over the entries, retrying when we find ourselves in a deleted
 98 * node and randomly pausing the iteration.
 99 */
100static void *untagged_iteration_fn(void *arg)
101{
102	XA_STATE(xas, &array, 0);
103	void *entry;
104
105	rcu_register_thread();
106
107	while (!test_complete) {
108		xas_set(&xas, 0);
109		rcu_read_lock();
110		xas_for_each(&xas, entry, ULONG_MAX) {
111			if (xas_retry(&xas, entry))
112				continue;
113
114			if (rand_r(&seeds[1]) % 50 == 0) {
115				xas_pause(&xas);
116				rcu_read_unlock();
117				rcu_barrier();
118				rcu_read_lock();
119			}
120		}
121		rcu_read_unlock();
122	}
123
124	rcu_unregister_thread();
125
126	return NULL;
127}
128
129/*
130 * Randomly remove entries to help induce retries in the
131 * two iteration functions.
132 */
133static void *remove_entries_fn(void *arg)
134{
135	rcu_register_thread();
136
137	while (!test_complete) {
138		int pgoff;
139		struct item *item;
140
141		pgoff = rand_r(&seeds[2]) % MAX_IDX;
142
143		item = xa_erase(&array, pgoff);
144		if (item)
145			item_free(item, pgoff);
146	}
147
148	rcu_unregister_thread();
149
150	return NULL;
151}
152
153static void *tag_entries_fn(void *arg)
154{
155	rcu_register_thread();
156
157	while (!test_complete) {
158		tag_tagged_items(&array, 0, MAX_IDX, 10, TAG, NEW_TAG);
159	}
160	rcu_unregister_thread();
161	return NULL;
162}
163
164/* This is a unit test for a bug found by the syzkaller tester */
165void iteration_test(unsigned order, unsigned test_duration)
166{
167	int i;
168
169	printv(1, "Running %siteration tests for %d seconds\n",
170			order > 0 ? "multiorder " : "", test_duration);
171
172	max_order = order;
173	test_complete = false;
174
175	for (i = 0; i < 3; i++)
176		seeds[i] = rand();
177
178	if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) {
179		perror("create tagged iteration thread");
180		exit(1);
181	}
182	if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) {
183		perror("create untagged iteration thread");
184		exit(1);
185	}
186	if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) {
187		perror("create add entry thread");
188		exit(1);
189	}
190	if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) {
191		perror("create remove entry thread");
192		exit(1);
193	}
194	if (pthread_create(&threads[4], NULL, tag_entries_fn, NULL)) {
195		perror("create tag entry thread");
196		exit(1);
197	}
198
199	sleep(test_duration);
200	test_complete = true;
201
202	for (i = 0; i < NUM_THREADS; i++) {
203		if (pthread_join(threads[i], NULL)) {
204			perror("pthread_join");
205			exit(1);
206		}
207	}
208
209	item_kill_tree(&array);
210}
v5.9
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * iteration_check.c: test races having to do with xarray iteration
  4 * Copyright (c) 2016 Intel Corporation
  5 * Author: Ross Zwisler <ross.zwisler@linux.intel.com>
  6 */
  7#include <pthread.h>
  8#include "test.h"
  9
 10#define NUM_THREADS	5
 11#define MAX_IDX		100
 12#define TAG		XA_MARK_0
 13#define NEW_TAG		XA_MARK_1
 14
 15static pthread_t threads[NUM_THREADS];
 16static unsigned int seeds[3];
 17static DEFINE_XARRAY(array);
 18static bool test_complete;
 19static int max_order;
 20
 21void my_item_insert(struct xarray *xa, unsigned long index)
 22{
 23	XA_STATE(xas, xa, index);
 24	struct item *item = item_create(index, 0);
 25	int order;
 26
 27retry:
 28	xas_lock(&xas);
 29	for (order = max_order; order >= 0; order--) {
 30		xas_set_order(&xas, index, order);
 31		item->order = order;
 32		if (xas_find_conflict(&xas))
 33			continue;
 34		xas_store(&xas, item);
 35		xas_set_mark(&xas, TAG);
 36		break;
 37	}
 38	xas_unlock(&xas);
 39	if (xas_nomem(&xas, GFP_KERNEL))
 40		goto retry;
 41	if (order < 0)
 42		free(item);
 43}
 44
 45/* relentlessly fill the array with tagged entries */
 46static void *add_entries_fn(void *arg)
 47{
 48	rcu_register_thread();
 49
 50	while (!test_complete) {
 51		unsigned long pgoff;
 52
 53		for (pgoff = 0; pgoff < MAX_IDX; pgoff++) {
 54			my_item_insert(&array, pgoff);
 55		}
 56	}
 57
 58	rcu_unregister_thread();
 59
 60	return NULL;
 61}
 62
 63/*
 64 * Iterate over tagged entries, retrying when we find ourselves in a deleted
 65 * node and randomly pausing the iteration.
 66 */
 67static void *tagged_iteration_fn(void *arg)
 68{
 69	XA_STATE(xas, &array, 0);
 70	void *entry;
 71
 72	rcu_register_thread();
 73
 74	while (!test_complete) {
 75		xas_set(&xas, 0);
 76		rcu_read_lock();
 77		xas_for_each_marked(&xas, entry, ULONG_MAX, TAG) {
 78			if (xas_retry(&xas, entry))
 79				continue;
 80
 81			if (rand_r(&seeds[0]) % 50 == 0) {
 82				xas_pause(&xas);
 83				rcu_read_unlock();
 84				rcu_barrier();
 85				rcu_read_lock();
 86			}
 87		}
 88		rcu_read_unlock();
 89	}
 90
 91	rcu_unregister_thread();
 92
 93	return NULL;
 94}
 95
 96/*
 97 * Iterate over the entries, retrying when we find ourselves in a deleted
 98 * node and randomly pausing the iteration.
 99 */
100static void *untagged_iteration_fn(void *arg)
101{
102	XA_STATE(xas, &array, 0);
103	void *entry;
104
105	rcu_register_thread();
106
107	while (!test_complete) {
108		xas_set(&xas, 0);
109		rcu_read_lock();
110		xas_for_each(&xas, entry, ULONG_MAX) {
111			if (xas_retry(&xas, entry))
112				continue;
113
114			if (rand_r(&seeds[1]) % 50 == 0) {
115				xas_pause(&xas);
116				rcu_read_unlock();
117				rcu_barrier();
118				rcu_read_lock();
119			}
120		}
121		rcu_read_unlock();
122	}
123
124	rcu_unregister_thread();
125
126	return NULL;
127}
128
129/*
130 * Randomly remove entries to help induce retries in the
131 * two iteration functions.
132 */
133static void *remove_entries_fn(void *arg)
134{
135	rcu_register_thread();
136
137	while (!test_complete) {
138		int pgoff;
139		struct item *item;
140
141		pgoff = rand_r(&seeds[2]) % MAX_IDX;
142
143		item = xa_erase(&array, pgoff);
144		if (item)
145			item_free(item, pgoff);
146	}
147
148	rcu_unregister_thread();
149
150	return NULL;
151}
152
153static void *tag_entries_fn(void *arg)
154{
155	rcu_register_thread();
156
157	while (!test_complete) {
158		tag_tagged_items(&array, 0, MAX_IDX, 10, TAG, NEW_TAG);
159	}
160	rcu_unregister_thread();
161	return NULL;
162}
163
164/* This is a unit test for a bug found by the syzkaller tester */
165void iteration_test(unsigned order, unsigned test_duration)
166{
167	int i;
168
169	printv(1, "Running %siteration tests for %d seconds\n",
170			order > 0 ? "multiorder " : "", test_duration);
171
172	max_order = order;
173	test_complete = false;
174
175	for (i = 0; i < 3; i++)
176		seeds[i] = rand();
177
178	if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) {
179		perror("create tagged iteration thread");
180		exit(1);
181	}
182	if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) {
183		perror("create untagged iteration thread");
184		exit(1);
185	}
186	if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) {
187		perror("create add entry thread");
188		exit(1);
189	}
190	if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) {
191		perror("create remove entry thread");
192		exit(1);
193	}
194	if (pthread_create(&threads[4], NULL, tag_entries_fn, NULL)) {
195		perror("create tag entry thread");
196		exit(1);
197	}
198
199	sleep(test_duration);
200	test_complete = true;
201
202	for (i = 0; i < NUM_THREADS; i++) {
203		if (pthread_join(threads[i], NULL)) {
204			perror("pthread_join");
205			exit(1);
206		}
207	}
208
209	item_kill_tree(&array);
210}