aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorMatthew Wilcox <willy@infradead.org>2017-12-04 00:11:48 -0500
committerMatthew Wilcox <willy@infradead.org>2018-10-21 10:45:59 -0400
commit2264f5132fe45571139727ebdeb78696b35d1506 (patch)
tree6982c4c48af09fc39c1faf5da5b39c5d4fc41ad0 /lib
parent4e99d4e9579d3b950bf4b38d0d64eb1b9be78761 (diff)
xarray: Add xas_create_range
This hopefully temporary function is useful for users who have not yet been converted to multi-index entries. Signed-off-by: Matthew Wilcox <willy@infradead.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/test_xarray.c119
-rw-r--r--lib/xarray.c50
2 files changed, 169 insertions, 0 deletions
diff --git a/lib/test_xarray.c b/lib/test_xarray.c
index 8eba3de1baea..703370015d10 100644
--- a/lib/test_xarray.c
+++ b/lib/test_xarray.c
@@ -646,6 +646,124 @@ static noinline void check_move(struct xarray *xa)
646 check_move_small(xa, (1UL << i) - 1); 646 check_move_small(xa, (1UL << i) - 1);
647} 647}
648 648
649static noinline void xa_store_many_order(struct xarray *xa,
650 unsigned long index, unsigned order)
651{
652 XA_STATE_ORDER(xas, xa, index, order);
653 unsigned int i = 0;
654
655 do {
656 xas_lock(&xas);
657 XA_BUG_ON(xa, xas_find_conflict(&xas));
658 xas_create_range(&xas);
659 if (xas_error(&xas))
660 goto unlock;
661 for (i = 0; i < (1U << order); i++) {
662 XA_BUG_ON(xa, xas_store(&xas, xa_mk_value(index + i)));
663 xas_next(&xas);
664 }
665unlock:
666 xas_unlock(&xas);
667 } while (xas_nomem(&xas, GFP_KERNEL));
668
669 XA_BUG_ON(xa, xas_error(&xas));
670}
671
672static noinline void check_create_range_1(struct xarray *xa,
673 unsigned long index, unsigned order)
674{
675 unsigned long i;
676
677 xa_store_many_order(xa, index, order);
678 for (i = index; i < index + (1UL << order); i++)
679 xa_erase_index(xa, i);
680 XA_BUG_ON(xa, !xa_empty(xa));
681}
682
683static noinline void check_create_range_2(struct xarray *xa, unsigned order)
684{
685 unsigned long i;
686 unsigned long nr = 1UL << order;
687
688 for (i = 0; i < nr * nr; i += nr)
689 xa_store_many_order(xa, i, order);
690 for (i = 0; i < nr * nr; i++)
691 xa_erase_index(xa, i);
692 XA_BUG_ON(xa, !xa_empty(xa));
693}
694
695static noinline void check_create_range_3(void)
696{
697 XA_STATE(xas, NULL, 0);
698 xas_set_err(&xas, -EEXIST);
699 xas_create_range(&xas);
700 XA_BUG_ON(NULL, xas_error(&xas) != -EEXIST);
701}
702
703static noinline void check_create_range_4(struct xarray *xa,
704 unsigned long index, unsigned order)
705{
706 XA_STATE_ORDER(xas, xa, index, order);
707 unsigned long base = xas.xa_index;
708 unsigned long i = 0;
709
710 xa_store_index(xa, index, GFP_KERNEL);
711 do {
712 xas_lock(&xas);
713 xas_create_range(&xas);
714 if (xas_error(&xas))
715 goto unlock;
716 for (i = 0; i < (1UL << order); i++) {
717 void *old = xas_store(&xas, xa_mk_value(base + i));
718 if (xas.xa_index == index)
719 XA_BUG_ON(xa, old != xa_mk_value(base + i));
720 else
721 XA_BUG_ON(xa, old != NULL);
722 xas_next(&xas);
723 }
724unlock:
725 xas_unlock(&xas);
726 } while (xas_nomem(&xas, GFP_KERNEL));
727
728 XA_BUG_ON(xa, xas_error(&xas));
729
730 for (i = base; i < base + (1UL << order); i++)
731 xa_erase_index(xa, i);
732 XA_BUG_ON(xa, !xa_empty(xa));
733}
734
735static noinline void check_create_range(struct xarray *xa)
736{
737 unsigned int order;
738 unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 12 : 1;
739
740 for (order = 0; order < max_order; order++) {
741 check_create_range_1(xa, 0, order);
742 check_create_range_1(xa, 1U << order, order);
743 check_create_range_1(xa, 2U << order, order);
744 check_create_range_1(xa, 3U << order, order);
745 check_create_range_1(xa, 1U << 24, order);
746 if (order < 10)
747 check_create_range_2(xa, order);
748
749 check_create_range_4(xa, 0, order);
750 check_create_range_4(xa, 1U << order, order);
751 check_create_range_4(xa, 2U << order, order);
752 check_create_range_4(xa, 3U << order, order);
753 check_create_range_4(xa, 1U << 24, order);
754
755 check_create_range_4(xa, 1, order);
756 check_create_range_4(xa, (1U << order) + 1, order);
757 check_create_range_4(xa, (2U << order) + 1, order);
758 check_create_range_4(xa, (2U << order) - 1, order);
759 check_create_range_4(xa, (3U << order) + 1, order);
760 check_create_range_4(xa, (3U << order) - 1, order);
761 check_create_range_4(xa, (1U << 24) + 1, order);
762 }
763
764 check_create_range_3();
765}
766
649static noinline void check_destroy(struct xarray *xa) 767static noinline void check_destroy(struct xarray *xa)
650{ 768{
651 unsigned long index; 769 unsigned long index;
@@ -694,6 +812,7 @@ static int xarray_checks(void)
694 check_find(&array); 812 check_find(&array);
695 check_destroy(&array); 813 check_destroy(&array);
696 check_move(&array); 814 check_move(&array);
815 check_create_range(&array);
697 check_store_iter(&array); 816 check_store_iter(&array);
698 817
699 printk("XArray: %u of %u tests passed\n", tests_passed, tests_run); 818 printk("XArray: %u of %u tests passed\n", tests_passed, tests_run);
diff --git a/lib/xarray.c b/lib/xarray.c
index 41f8ebc651f5..ff37516fe832 100644
--- a/lib/xarray.c
+++ b/lib/xarray.c
@@ -637,6 +637,56 @@ static void *xas_create(struct xa_state *xas)
637 return entry; 637 return entry;
638} 638}
639 639
640/**
641 * xas_create_range() - Ensure that stores to this range will succeed
642 * @xas: XArray operation state.
643 *
644 * Creates all of the slots in the range covered by @xas. Sets @xas to
645 * create single-index entries and positions it at the beginning of the
646 * range. This is for the benefit of users which have not yet been
647 * converted to use multi-index entries.
648 */
649void xas_create_range(struct xa_state *xas)
650{
651 unsigned long index = xas->xa_index;
652 unsigned char shift = xas->xa_shift;
653 unsigned char sibs = xas->xa_sibs;
654
655 xas->xa_index |= ((sibs + 1) << shift) - 1;
656 if (xas_is_node(xas) && xas->xa_node->shift == xas->xa_shift)
657 xas->xa_offset |= sibs;
658 xas->xa_shift = 0;
659 xas->xa_sibs = 0;
660
661 for (;;) {
662 xas_create(xas);
663 if (xas_error(xas))
664 goto restore;
665 if (xas->xa_index <= (index | XA_CHUNK_MASK))
666 goto success;
667 xas->xa_index -= XA_CHUNK_SIZE;
668
669 for (;;) {
670 struct xa_node *node = xas->xa_node;
671 xas->xa_node = xa_parent_locked(xas->xa, node);
672 xas->xa_offset = node->offset - 1;
673 if (node->offset != 0)
674 break;
675 }
676 }
677
678restore:
679 xas->xa_shift = shift;
680 xas->xa_sibs = sibs;
681 xas->xa_index = index;
682 return;
683success:
684 xas->xa_index = index;
685 if (xas->xa_node)
686 xas_set_offset(xas);
687}
688EXPORT_SYMBOL_GPL(xas_create_range);
689
640static void update_node(struct xa_state *xas, struct xa_node *node, 690static void update_node(struct xa_state *xas, struct xa_node *node,
641 int count, int values) 691 int count, int values)
642{ 692{