diff options
author | Matthew Wilcox <willy@infradead.org> | 2017-12-04 00:11:48 -0500 |
---|---|---|
committer | Matthew Wilcox <willy@infradead.org> | 2018-10-21 10:45:59 -0400 |
commit | 2264f5132fe45571139727ebdeb78696b35d1506 (patch) | |
tree | 6982c4c48af09fc39c1faf5da5b39c5d4fc41ad0 /lib | |
parent | 4e99d4e9579d3b950bf4b38d0d64eb1b9be78761 (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.c | 119 | ||||
-rw-r--r-- | lib/xarray.c | 50 |
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 | ||
649 | static 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 | } | ||
665 | unlock: | ||
666 | xas_unlock(&xas); | ||
667 | } while (xas_nomem(&xas, GFP_KERNEL)); | ||
668 | |||
669 | XA_BUG_ON(xa, xas_error(&xas)); | ||
670 | } | ||
671 | |||
672 | static 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 | |||
683 | static 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 | |||
695 | static 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 | |||
703 | static 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 | } | ||
724 | unlock: | ||
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 | |||
735 | static 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 | |||
649 | static noinline void check_destroy(struct xarray *xa) | 767 | static 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 | */ | ||
649 | void 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 | |||
678 | restore: | ||
679 | xas->xa_shift = shift; | ||
680 | xas->xa_sibs = sibs; | ||
681 | xas->xa_index = index; | ||
682 | return; | ||
683 | success: | ||
684 | xas->xa_index = index; | ||
685 | if (xas->xa_node) | ||
686 | xas_set_offset(xas); | ||
687 | } | ||
688 | EXPORT_SYMBOL_GPL(xas_create_range); | ||
689 | |||
640 | static void update_node(struct xa_state *xas, struct xa_node *node, | 690 | static void update_node(struct xa_state *xas, struct xa_node *node, |
641 | int count, int values) | 691 | int count, int values) |
642 | { | 692 | { |