diff options
| -rw-r--r-- | MAINTAINERS | 1 | ||||
| -rw-r--r-- | fs/hfsplus/super.c | 1 | ||||
| -rw-r--r-- | include/linux/mm.h | 7 | ||||
| -rw-r--r-- | lib/radix-tree.c | 6 | ||||
| -rw-r--r-- | lib/test_bitmap.c | 21 | ||||
| -rw-r--r-- | mm/Kconfig | 1 | ||||
| -rw-r--r-- | tools/include/linux/spinlock.h | 3 | ||||
| -rw-r--r-- | tools/testing/radix-tree/Makefile | 6 | ||||
| -rw-r--r-- | tools/testing/radix-tree/multiorder.c | 63 | ||||
| -rw-r--r-- | tools/testing/radix-tree/test.c | 19 | ||||
| -rw-r--r-- | tools/testing/radix-tree/test.h | 3 |
11 files changed, 116 insertions, 15 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 4de8a5d9ed91..d155d1e0dbc2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -7698,6 +7698,7 @@ KERNEL SELFTEST FRAMEWORK | |||
| 7698 | M: Shuah Khan <shuah@kernel.org> | 7698 | M: Shuah Khan <shuah@kernel.org> |
| 7699 | L: linux-kselftest@vger.kernel.org | 7699 | L: linux-kselftest@vger.kernel.org |
| 7700 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git | 7700 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git |
| 7701 | Q: https://patchwork.kernel.org/project/linux-kselftest/list/ | ||
| 7701 | S: Maintained | 7702 | S: Maintained |
| 7702 | F: tools/testing/selftests/ | 7703 | F: tools/testing/selftests/ |
| 7703 | F: Documentation/dev-tools/kselftest* | 7704 | F: Documentation/dev-tools/kselftest* |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 513c357c734b..a6c0f54c48c3 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
| @@ -588,6 +588,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) | |||
| 588 | return 0; | 588 | return 0; |
| 589 | 589 | ||
| 590 | out_put_hidden_dir: | 590 | out_put_hidden_dir: |
| 591 | cancel_delayed_work_sync(&sbi->sync_work); | ||
| 591 | iput(sbi->hidden_dir); | 592 | iput(sbi->hidden_dir); |
| 592 | out_put_root: | 593 | out_put_root: |
| 593 | dput(sb->s_root); | 594 | dput(sb->s_root); |
diff --git a/include/linux/mm.h b/include/linux/mm.h index c080af584ddd..c6fa9a255dbf 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
| @@ -2466,6 +2466,13 @@ static inline vm_fault_t vmf_insert_pfn(struct vm_area_struct *vma, | |||
| 2466 | return VM_FAULT_NOPAGE; | 2466 | return VM_FAULT_NOPAGE; |
| 2467 | } | 2467 | } |
| 2468 | 2468 | ||
| 2469 | static inline vm_fault_t vmf_error(int err) | ||
| 2470 | { | ||
| 2471 | if (err == -ENOMEM) | ||
| 2472 | return VM_FAULT_OOM; | ||
| 2473 | return VM_FAULT_SIGBUS; | ||
| 2474 | } | ||
| 2475 | |||
| 2469 | struct page *follow_page_mask(struct vm_area_struct *vma, | 2476 | struct page *follow_page_mask(struct vm_area_struct *vma, |
| 2470 | unsigned long address, unsigned int foll_flags, | 2477 | unsigned long address, unsigned int foll_flags, |
| 2471 | unsigned int *page_mask); | 2478 | unsigned int *page_mask); |
diff --git a/lib/radix-tree.c b/lib/radix-tree.c index da9e10c827df..43e0cbedc3a0 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c | |||
| @@ -1612,11 +1612,9 @@ static void set_iter_tags(struct radix_tree_iter *iter, | |||
| 1612 | static void __rcu **skip_siblings(struct radix_tree_node **nodep, | 1612 | static void __rcu **skip_siblings(struct radix_tree_node **nodep, |
| 1613 | void __rcu **slot, struct radix_tree_iter *iter) | 1613 | void __rcu **slot, struct radix_tree_iter *iter) |
| 1614 | { | 1614 | { |
| 1615 | void *sib = node_to_entry(slot - 1); | ||
| 1616 | |||
| 1617 | while (iter->index < iter->next_index) { | 1615 | while (iter->index < iter->next_index) { |
| 1618 | *nodep = rcu_dereference_raw(*slot); | 1616 | *nodep = rcu_dereference_raw(*slot); |
| 1619 | if (*nodep && *nodep != sib) | 1617 | if (*nodep && !is_sibling_entry(iter->node, *nodep)) |
| 1620 | return slot; | 1618 | return slot; |
| 1621 | slot++; | 1619 | slot++; |
| 1622 | iter->index = __radix_tree_iter_add(iter, 1); | 1620 | iter->index = __radix_tree_iter_add(iter, 1); |
| @@ -1631,7 +1629,7 @@ void __rcu **__radix_tree_next_slot(void __rcu **slot, | |||
| 1631 | struct radix_tree_iter *iter, unsigned flags) | 1629 | struct radix_tree_iter *iter, unsigned flags) |
| 1632 | { | 1630 | { |
| 1633 | unsigned tag = flags & RADIX_TREE_ITER_TAG_MASK; | 1631 | unsigned tag = flags & RADIX_TREE_ITER_TAG_MASK; |
| 1634 | struct radix_tree_node *node = rcu_dereference_raw(*slot); | 1632 | struct radix_tree_node *node; |
| 1635 | 1633 | ||
| 1636 | slot = skip_siblings(&node, slot, iter); | 1634 | slot = skip_siblings(&node, slot, iter); |
| 1637 | 1635 | ||
diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index de16f7869fb1..6cd7d0740005 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c | |||
| @@ -331,23 +331,32 @@ static void noinline __init test_mem_optimisations(void) | |||
| 331 | unsigned int start, nbits; | 331 | unsigned int start, nbits; |
| 332 | 332 | ||
| 333 | for (start = 0; start < 1024; start += 8) { | 333 | for (start = 0; start < 1024; start += 8) { |
| 334 | memset(bmap1, 0x5a, sizeof(bmap1)); | ||
| 335 | memset(bmap2, 0x5a, sizeof(bmap2)); | ||
| 336 | for (nbits = 0; nbits < 1024 - start; nbits += 8) { | 334 | for (nbits = 0; nbits < 1024 - start; nbits += 8) { |
| 335 | memset(bmap1, 0x5a, sizeof(bmap1)); | ||
| 336 | memset(bmap2, 0x5a, sizeof(bmap2)); | ||
| 337 | |||
| 337 | bitmap_set(bmap1, start, nbits); | 338 | bitmap_set(bmap1, start, nbits); |
| 338 | __bitmap_set(bmap2, start, nbits); | 339 | __bitmap_set(bmap2, start, nbits); |
| 339 | if (!bitmap_equal(bmap1, bmap2, 1024)) | 340 | if (!bitmap_equal(bmap1, bmap2, 1024)) { |
| 340 | printk("set not equal %d %d\n", start, nbits); | 341 | printk("set not equal %d %d\n", start, nbits); |
| 341 | if (!__bitmap_equal(bmap1, bmap2, 1024)) | 342 | failed_tests++; |
| 343 | } | ||
| 344 | if (!__bitmap_equal(bmap1, bmap2, 1024)) { | ||
| 342 | printk("set not __equal %d %d\n", start, nbits); | 345 | printk("set not __equal %d %d\n", start, nbits); |
| 346 | failed_tests++; | ||
| 347 | } | ||
| 343 | 348 | ||
| 344 | bitmap_clear(bmap1, start, nbits); | 349 | bitmap_clear(bmap1, start, nbits); |
| 345 | __bitmap_clear(bmap2, start, nbits); | 350 | __bitmap_clear(bmap2, start, nbits); |
| 346 | if (!bitmap_equal(bmap1, bmap2, 1024)) | 351 | if (!bitmap_equal(bmap1, bmap2, 1024)) { |
| 347 | printk("clear not equal %d %d\n", start, nbits); | 352 | printk("clear not equal %d %d\n", start, nbits); |
| 348 | if (!__bitmap_equal(bmap1, bmap2, 1024)) | 353 | failed_tests++; |
| 354 | } | ||
| 355 | if (!__bitmap_equal(bmap1, bmap2, 1024)) { | ||
| 349 | printk("clear not __equal %d %d\n", start, | 356 | printk("clear not __equal %d %d\n", start, |
| 350 | nbits); | 357 | nbits); |
| 358 | failed_tests++; | ||
| 359 | } | ||
| 351 | } | 360 | } |
| 352 | } | 361 | } |
| 353 | } | 362 | } |
diff --git a/mm/Kconfig b/mm/Kconfig index d5004d82a1d6..e14c01513bfd 100644 --- a/mm/Kconfig +++ b/mm/Kconfig | |||
| @@ -636,6 +636,7 @@ config DEFERRED_STRUCT_PAGE_INIT | |||
| 636 | default n | 636 | default n |
| 637 | depends on NO_BOOTMEM | 637 | depends on NO_BOOTMEM |
| 638 | depends on !FLATMEM | 638 | depends on !FLATMEM |
| 639 | depends on !NEED_PER_CPU_KM | ||
| 639 | help | 640 | help |
| 640 | Ordinarily all struct pages are initialised during early boot in a | 641 | Ordinarily all struct pages are initialised during early boot in a |
| 641 | single thread. On very large machines this can take a considerable | 642 | single thread. On very large machines this can take a considerable |
diff --git a/tools/include/linux/spinlock.h b/tools/include/linux/spinlock.h index b21b586b9854..1738c0391da4 100644 --- a/tools/include/linux/spinlock.h +++ b/tools/include/linux/spinlock.h | |||
| @@ -6,8 +6,9 @@ | |||
| 6 | #include <stdbool.h> | 6 | #include <stdbool.h> |
| 7 | 7 | ||
| 8 | #define spinlock_t pthread_mutex_t | 8 | #define spinlock_t pthread_mutex_t |
| 9 | #define DEFINE_SPINLOCK(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER; | 9 | #define DEFINE_SPINLOCK(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER |
| 10 | #define __SPIN_LOCK_UNLOCKED(x) (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER | 10 | #define __SPIN_LOCK_UNLOCKED(x) (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER |
| 11 | #define spin_lock_init(x) pthread_mutex_init(x, NULL) | ||
| 11 | 12 | ||
| 12 | #define spin_lock_irqsave(x, f) (void)f, pthread_mutex_lock(x) | 13 | #define spin_lock_irqsave(x, f) (void)f, pthread_mutex_lock(x) |
| 13 | #define spin_unlock_irqrestore(x, f) (void)f, pthread_mutex_unlock(x) | 14 | #define spin_unlock_irqrestore(x, f) (void)f, pthread_mutex_unlock(x) |
diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile index fa7ee369b3c9..db66f8a0d4be 100644 --- a/tools/testing/radix-tree/Makefile +++ b/tools/testing/radix-tree/Makefile | |||
| @@ -17,7 +17,7 @@ ifeq ($(BUILD), 32) | |||
| 17 | LDFLAGS += -m32 | 17 | LDFLAGS += -m32 |
| 18 | endif | 18 | endif |
| 19 | 19 | ||
| 20 | targets: mapshift $(TARGETS) | 20 | targets: generated/map-shift.h $(TARGETS) |
| 21 | 21 | ||
| 22 | main: $(OFILES) | 22 | main: $(OFILES) |
| 23 | 23 | ||
| @@ -42,9 +42,7 @@ radix-tree.c: ../../../lib/radix-tree.c | |||
| 42 | idr.c: ../../../lib/idr.c | 42 | idr.c: ../../../lib/idr.c |
| 43 | sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@ | 43 | sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@ |
| 44 | 44 | ||
| 45 | .PHONY: mapshift | 45 | generated/map-shift.h: |
| 46 | |||
| 47 | mapshift: | ||
| 48 | @if ! grep -qws $(SHIFT) generated/map-shift.h; then \ | 46 | @if ! grep -qws $(SHIFT) generated/map-shift.h; then \ |
| 49 | echo "#define RADIX_TREE_MAP_SHIFT $(SHIFT)" > \ | 47 | echo "#define RADIX_TREE_MAP_SHIFT $(SHIFT)" > \ |
| 50 | generated/map-shift.h; \ | 48 | generated/map-shift.h; \ |
diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c index 59245b3d587c..7bf405638b0b 100644 --- a/tools/testing/radix-tree/multiorder.c +++ b/tools/testing/radix-tree/multiorder.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/radix-tree.h> | 16 | #include <linux/radix-tree.h> |
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
| 19 | #include <pthread.h> | ||
| 19 | 20 | ||
| 20 | #include "test.h" | 21 | #include "test.h" |
| 21 | 22 | ||
| @@ -624,6 +625,67 @@ static void multiorder_account(void) | |||
| 624 | item_kill_tree(&tree); | 625 | item_kill_tree(&tree); |
| 625 | } | 626 | } |
| 626 | 627 | ||
| 628 | bool stop_iteration = false; | ||
| 629 | |||
| 630 | static void *creator_func(void *ptr) | ||
| 631 | { | ||
| 632 | /* 'order' is set up to ensure we have sibling entries */ | ||
| 633 | unsigned int order = RADIX_TREE_MAP_SHIFT - 1; | ||
| 634 | struct radix_tree_root *tree = ptr; | ||
| 635 | int i; | ||
| 636 | |||
| 637 | for (i = 0; i < 10000; i++) { | ||
| 638 | item_insert_order(tree, 0, order); | ||
| 639 | item_delete_rcu(tree, 0); | ||
| 640 | } | ||
| 641 | |||
| 642 | stop_iteration = true; | ||
| 643 | return NULL; | ||
| 644 | } | ||
| 645 | |||
| 646 | static void *iterator_func(void *ptr) | ||
| 647 | { | ||
| 648 | struct radix_tree_root *tree = ptr; | ||
| 649 | struct radix_tree_iter iter; | ||
| 650 | struct item *item; | ||
| 651 | void **slot; | ||
| 652 | |||
| 653 | while (!stop_iteration) { | ||
| 654 | rcu_read_lock(); | ||
| 655 | radix_tree_for_each_slot(slot, tree, &iter, 0) { | ||
| 656 | item = radix_tree_deref_slot(slot); | ||
| 657 | |||
| 658 | if (!item) | ||
| 659 | continue; | ||
| 660 | if (radix_tree_deref_retry(item)) { | ||
| 661 | slot = radix_tree_iter_retry(&iter); | ||
| 662 | continue; | ||
| 663 | } | ||
| 664 | |||
| 665 | item_sanity(item, iter.index); | ||
| 666 | } | ||
| 667 | rcu_read_unlock(); | ||
| 668 | } | ||
| 669 | return NULL; | ||
| 670 | } | ||
| 671 | |||
| 672 | static void multiorder_iteration_race(void) | ||
| 673 | { | ||
| 674 | const int num_threads = sysconf(_SC_NPROCESSORS_ONLN); | ||
| 675 | pthread_t worker_thread[num_threads]; | ||
| 676 | RADIX_TREE(tree, GFP_KERNEL); | ||
| 677 | int i; | ||
| 678 | |||
| 679 | pthread_create(&worker_thread[0], NULL, &creator_func, &tree); | ||
| 680 | for (i = 1; i < num_threads; i++) | ||
| 681 | pthread_create(&worker_thread[i], NULL, &iterator_func, &tree); | ||
| 682 | |||
| 683 | for (i = 0; i < num_threads; i++) | ||
| 684 | pthread_join(worker_thread[i], NULL); | ||
| 685 | |||
| 686 | item_kill_tree(&tree); | ||
| 687 | } | ||
| 688 | |||
| 627 | void multiorder_checks(void) | 689 | void multiorder_checks(void) |
| 628 | { | 690 | { |
| 629 | int i; | 691 | int i; |
| @@ -644,6 +706,7 @@ void multiorder_checks(void) | |||
| 644 | multiorder_join(); | 706 | multiorder_join(); |
| 645 | multiorder_split(); | 707 | multiorder_split(); |
| 646 | multiorder_account(); | 708 | multiorder_account(); |
| 709 | multiorder_iteration_race(); | ||
| 647 | 710 | ||
| 648 | radix_tree_cpu_dead(0); | 711 | radix_tree_cpu_dead(0); |
| 649 | } | 712 | } |
diff --git a/tools/testing/radix-tree/test.c b/tools/testing/radix-tree/test.c index 5978ab1f403d..def6015570b2 100644 --- a/tools/testing/radix-tree/test.c +++ b/tools/testing/radix-tree/test.c | |||
| @@ -75,6 +75,25 @@ int item_delete(struct radix_tree_root *root, unsigned long index) | |||
| 75 | return 0; | 75 | return 0; |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | static void item_free_rcu(struct rcu_head *head) | ||
| 79 | { | ||
| 80 | struct item *item = container_of(head, struct item, rcu_head); | ||
| 81 | |||
| 82 | free(item); | ||
| 83 | } | ||
| 84 | |||
| 85 | int item_delete_rcu(struct radix_tree_root *root, unsigned long index) | ||
| 86 | { | ||
| 87 | struct item *item = radix_tree_delete(root, index); | ||
| 88 | |||
| 89 | if (item) { | ||
| 90 | item_sanity(item, index); | ||
| 91 | call_rcu(&item->rcu_head, item_free_rcu); | ||
| 92 | return 1; | ||
| 93 | } | ||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 78 | void item_check_present(struct radix_tree_root *root, unsigned long index) | 97 | void item_check_present(struct radix_tree_root *root, unsigned long index) |
| 79 | { | 98 | { |
| 80 | struct item *item; | 99 | struct item *item; |
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h index d9c031dbeb1a..31f1d9b6f506 100644 --- a/tools/testing/radix-tree/test.h +++ b/tools/testing/radix-tree/test.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <linux/rcupdate.h> | 5 | #include <linux/rcupdate.h> |
| 6 | 6 | ||
| 7 | struct item { | 7 | struct item { |
| 8 | struct rcu_head rcu_head; | ||
| 8 | unsigned long index; | 9 | unsigned long index; |
| 9 | unsigned int order; | 10 | unsigned int order; |
| 10 | }; | 11 | }; |
| @@ -12,9 +13,11 @@ struct item { | |||
| 12 | struct item *item_create(unsigned long index, unsigned int order); | 13 | struct item *item_create(unsigned long index, unsigned int order); |
| 13 | int __item_insert(struct radix_tree_root *root, struct item *item); | 14 | int __item_insert(struct radix_tree_root *root, struct item *item); |
| 14 | int item_insert(struct radix_tree_root *root, unsigned long index); | 15 | int item_insert(struct radix_tree_root *root, unsigned long index); |
| 16 | void item_sanity(struct item *item, unsigned long index); | ||
| 15 | int item_insert_order(struct radix_tree_root *root, unsigned long index, | 17 | int item_insert_order(struct radix_tree_root *root, unsigned long index, |
| 16 | unsigned order); | 18 | unsigned order); |
| 17 | int item_delete(struct radix_tree_root *root, unsigned long index); | 19 | int item_delete(struct radix_tree_root *root, unsigned long index); |
| 20 | int item_delete_rcu(struct radix_tree_root *root, unsigned long index); | ||
| 18 | struct item *item_lookup(struct radix_tree_root *root, unsigned long index); | 21 | struct item *item_lookup(struct radix_tree_root *root, unsigned long index); |
| 19 | 22 | ||
| 20 | void item_check_present(struct radix_tree_root *root, unsigned long index); | 23 | void item_check_present(struct radix_tree_root *root, unsigned long index); |
