diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-05-19 00:24:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-05-19 00:24:26 -0400 |
commit | 73fcb1a370c76b202d406e95d9dabb76eaccf484 (patch) | |
tree | 78997fee9c78677955d414a699ce965fb8a21065 | |
parent | 10a2f87485b9fb7bec1a50305d4a3ec74aa8058c (diff) | |
parent | 66072c29328717072fd84aaff3e070e3f008ba77 (diff) |
Merge branch 'akpm' (patches from Andrew)
Merge misc fixes from Andrew Morton:
"10 fixes"
* emailed patches from Andrew Morton <akpm@linux-foundation.org>:
hfsplus: stop workqueue when fill_super() failed
mm: don't allow deferred pages with NEED_PER_CPU_KM
MAINTAINERS: add Q: entry to kselftest for patchwork project
radix tree: fix multi-order iteration race
radix tree test suite: multi-order iteration race
radix tree test suite: add item_delete_rcu()
radix tree test suite: fix compilation issue
radix tree test suite: fix mapshift build target
include/linux/mm.h: add new inline function vmf_error()
lib/test_bitmap.c: fix bitmap optimisation tests to report errors correctly
-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); |