1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
22d6f45b8SKonstantin Khlebnikov /*
32d6f45b8SKonstantin Khlebnikov  * Regression3
42d6f45b8SKonstantin Khlebnikov  * Description:
52d6f45b8SKonstantin Khlebnikov  * Helper radix_tree_iter_retry resets next_index to the current index.
62d6f45b8SKonstantin Khlebnikov  * In following radix_tree_next_slot current chunk size becomes zero.
72d6f45b8SKonstantin Khlebnikov  * This isn't checked and it tries to dereference null pointer in slot.
82d6f45b8SKonstantin Khlebnikov  *
9148deab2SMatthew Wilcox  * Helper radix_tree_iter_resume reset slot to NULL and next_index to index + 1,
107475851fSKonstantin Khlebnikov  * for tagger iteraction it also must reset cached tags in iterator to abort
117475851fSKonstantin Khlebnikov  * next radix_tree_next_slot and go to slow-path into radix_tree_next_chunk.
127475851fSKonstantin Khlebnikov  *
132d6f45b8SKonstantin Khlebnikov  * Running:
142d6f45b8SKonstantin Khlebnikov  * This test should run to completion immediately. The above bug would
152d6f45b8SKonstantin Khlebnikov  * cause it to segfault.
162d6f45b8SKonstantin Khlebnikov  *
172d6f45b8SKonstantin Khlebnikov  * Upstream commit:
182d6f45b8SKonstantin Khlebnikov  * Not yet
192d6f45b8SKonstantin Khlebnikov  */
202d6f45b8SKonstantin Khlebnikov #include <linux/kernel.h>
212d6f45b8SKonstantin Khlebnikov #include <linux/gfp.h>
222d6f45b8SKonstantin Khlebnikov #include <linux/slab.h>
232d6f45b8SKonstantin Khlebnikov #include <linux/radix-tree.h>
242d6f45b8SKonstantin Khlebnikov #include <stdlib.h>
252d6f45b8SKonstantin Khlebnikov #include <stdio.h>
262d6f45b8SKonstantin Khlebnikov 
272d6f45b8SKonstantin Khlebnikov #include "regression.h"
282d6f45b8SKonstantin Khlebnikov 
regression3_test(void)292d6f45b8SKonstantin Khlebnikov void regression3_test(void)
302d6f45b8SKonstantin Khlebnikov {
312d6f45b8SKonstantin Khlebnikov 	RADIX_TREE(root, GFP_KERNEL);
327475851fSKonstantin Khlebnikov 	void *ptr0 = (void *)4ul;
337475851fSKonstantin Khlebnikov 	void *ptr = (void *)8ul;
342d6f45b8SKonstantin Khlebnikov 	struct radix_tree_iter iter;
352d6f45b8SKonstantin Khlebnikov 	void **slot;
362d6f45b8SKonstantin Khlebnikov 	bool first;
372d6f45b8SKonstantin Khlebnikov 
3873bc029bSRehas Sachdeva 	printv(1, "running regression test 3 (should take milliseconds)\n");
392d6f45b8SKonstantin Khlebnikov 
407475851fSKonstantin Khlebnikov 	radix_tree_insert(&root, 0, ptr0);
412d6f45b8SKonstantin Khlebnikov 	radix_tree_tag_set(&root, 0, 0);
422d6f45b8SKonstantin Khlebnikov 
432d6f45b8SKonstantin Khlebnikov 	first = true;
442d6f45b8SKonstantin Khlebnikov 	radix_tree_for_each_tagged(slot, &root, &iter, 0, 0) {
4573bc029bSRehas Sachdeva 		printv(2, "tagged %ld %p\n", iter.index, *slot);
462d6f45b8SKonstantin Khlebnikov 		if (first) {
472d6f45b8SKonstantin Khlebnikov 			radix_tree_insert(&root, 1, ptr);
482d6f45b8SKonstantin Khlebnikov 			radix_tree_tag_set(&root, 1, 0);
492d6f45b8SKonstantin Khlebnikov 			first = false;
502d6f45b8SKonstantin Khlebnikov 		}
512d6f45b8SKonstantin Khlebnikov 		if (radix_tree_deref_retry(*slot)) {
5273bc029bSRehas Sachdeva 			printv(2, "retry at %ld\n", iter.index);
532d6f45b8SKonstantin Khlebnikov 			slot = radix_tree_iter_retry(&iter);
542d6f45b8SKonstantin Khlebnikov 			continue;
552d6f45b8SKonstantin Khlebnikov 		}
562d6f45b8SKonstantin Khlebnikov 	}
572d6f45b8SKonstantin Khlebnikov 	radix_tree_delete(&root, 1);
582d6f45b8SKonstantin Khlebnikov 
592d6f45b8SKonstantin Khlebnikov 	first = true;
602d6f45b8SKonstantin Khlebnikov 	radix_tree_for_each_slot(slot, &root, &iter, 0) {
6173bc029bSRehas Sachdeva 		printv(2, "slot %ld %p\n", iter.index, *slot);
622d6f45b8SKonstantin Khlebnikov 		if (first) {
632d6f45b8SKonstantin Khlebnikov 			radix_tree_insert(&root, 1, ptr);
642d6f45b8SKonstantin Khlebnikov 			first = false;
652d6f45b8SKonstantin Khlebnikov 		}
662d6f45b8SKonstantin Khlebnikov 		if (radix_tree_deref_retry(*slot)) {
6773bc029bSRehas Sachdeva 			printv(2, "retry at %ld\n", iter.index);
682d6f45b8SKonstantin Khlebnikov 			slot = radix_tree_iter_retry(&iter);
692d6f45b8SKonstantin Khlebnikov 			continue;
702d6f45b8SKonstantin Khlebnikov 		}
712d6f45b8SKonstantin Khlebnikov 	}
722d6f45b8SKonstantin Khlebnikov 
737475851fSKonstantin Khlebnikov 	radix_tree_for_each_slot(slot, &root, &iter, 0) {
7473bc029bSRehas Sachdeva 		printv(2, "slot %ld %p\n", iter.index, *slot);
757475851fSKonstantin Khlebnikov 		if (!iter.index) {
7673bc029bSRehas Sachdeva 			printv(2, "next at %ld\n", iter.index);
77148deab2SMatthew Wilcox 			slot = radix_tree_iter_resume(slot, &iter);
787475851fSKonstantin Khlebnikov 		}
797475851fSKonstantin Khlebnikov 	}
807475851fSKonstantin Khlebnikov 
817475851fSKonstantin Khlebnikov 	radix_tree_tag_set(&root, 0, 0);
827475851fSKonstantin Khlebnikov 	radix_tree_tag_set(&root, 1, 0);
837475851fSKonstantin Khlebnikov 	radix_tree_for_each_tagged(slot, &root, &iter, 0, 0) {
8473bc029bSRehas Sachdeva 		printv(2, "tagged %ld %p\n", iter.index, *slot);
857475851fSKonstantin Khlebnikov 		if (!iter.index) {
8673bc029bSRehas Sachdeva 			printv(2, "next at %ld\n", iter.index);
87148deab2SMatthew Wilcox 			slot = radix_tree_iter_resume(slot, &iter);
887475851fSKonstantin Khlebnikov 		}
897475851fSKonstantin Khlebnikov 	}
907475851fSKonstantin Khlebnikov 
912d6f45b8SKonstantin Khlebnikov 	radix_tree_delete(&root, 0);
922d6f45b8SKonstantin Khlebnikov 	radix_tree_delete(&root, 1);
932d6f45b8SKonstantin Khlebnikov 
9473bc029bSRehas Sachdeva 	printv(1, "regression test 3 passed\n");
952d6f45b8SKonstantin Khlebnikov }
96