Commit 73fcb1a3 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 10a2f874 66072c29
...@@ -7698,6 +7698,7 @@ KERNEL SELFTEST FRAMEWORK ...@@ -7698,6 +7698,7 @@ KERNEL SELFTEST FRAMEWORK
M: Shuah Khan <shuah@kernel.org> M: Shuah Khan <shuah@kernel.org>
L: linux-kselftest@vger.kernel.org L: linux-kselftest@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git
Q: https://patchwork.kernel.org/project/linux-kselftest/list/
S: Maintained S: Maintained
F: tools/testing/selftests/ F: tools/testing/selftests/
F: Documentation/dev-tools/kselftest* F: Documentation/dev-tools/kselftest*
......
...@@ -588,6 +588,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) ...@@ -588,6 +588,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
return 0; return 0;
out_put_hidden_dir: out_put_hidden_dir:
cancel_delayed_work_sync(&sbi->sync_work);
iput(sbi->hidden_dir); iput(sbi->hidden_dir);
out_put_root: out_put_root:
dput(sb->s_root); dput(sb->s_root);
......
...@@ -2466,6 +2466,13 @@ static inline vm_fault_t vmf_insert_pfn(struct vm_area_struct *vma, ...@@ -2466,6 +2466,13 @@ static inline vm_fault_t vmf_insert_pfn(struct vm_area_struct *vma,
return VM_FAULT_NOPAGE; return VM_FAULT_NOPAGE;
} }
static inline vm_fault_t vmf_error(int err)
{
if (err == -ENOMEM)
return VM_FAULT_OOM;
return VM_FAULT_SIGBUS;
}
struct page *follow_page_mask(struct vm_area_struct *vma, struct page *follow_page_mask(struct vm_area_struct *vma,
unsigned long address, unsigned int foll_flags, unsigned long address, unsigned int foll_flags,
unsigned int *page_mask); unsigned int *page_mask);
......
...@@ -1612,11 +1612,9 @@ static void set_iter_tags(struct radix_tree_iter *iter, ...@@ -1612,11 +1612,9 @@ static void set_iter_tags(struct radix_tree_iter *iter,
static void __rcu **skip_siblings(struct radix_tree_node **nodep, static void __rcu **skip_siblings(struct radix_tree_node **nodep,
void __rcu **slot, struct radix_tree_iter *iter) void __rcu **slot, struct radix_tree_iter *iter)
{ {
void *sib = node_to_entry(slot - 1);
while (iter->index < iter->next_index) { while (iter->index < iter->next_index) {
*nodep = rcu_dereference_raw(*slot); *nodep = rcu_dereference_raw(*slot);
if (*nodep && *nodep != sib) if (*nodep && !is_sibling_entry(iter->node, *nodep))
return slot; return slot;
slot++; slot++;
iter->index = __radix_tree_iter_add(iter, 1); iter->index = __radix_tree_iter_add(iter, 1);
...@@ -1631,7 +1629,7 @@ void __rcu **__radix_tree_next_slot(void __rcu **slot, ...@@ -1631,7 +1629,7 @@ void __rcu **__radix_tree_next_slot(void __rcu **slot,
struct radix_tree_iter *iter, unsigned flags) struct radix_tree_iter *iter, unsigned flags)
{ {
unsigned tag = flags & RADIX_TREE_ITER_TAG_MASK; unsigned tag = flags & RADIX_TREE_ITER_TAG_MASK;
struct radix_tree_node *node = rcu_dereference_raw(*slot); struct radix_tree_node *node;
slot = skip_siblings(&node, slot, iter); slot = skip_siblings(&node, slot, iter);
......
...@@ -331,23 +331,32 @@ static void noinline __init test_mem_optimisations(void) ...@@ -331,23 +331,32 @@ static void noinline __init test_mem_optimisations(void)
unsigned int start, nbits; unsigned int start, nbits;
for (start = 0; start < 1024; start += 8) { for (start = 0; start < 1024; start += 8) {
for (nbits = 0; nbits < 1024 - start; nbits += 8) {
memset(bmap1, 0x5a, sizeof(bmap1)); memset(bmap1, 0x5a, sizeof(bmap1));
memset(bmap2, 0x5a, sizeof(bmap2)); memset(bmap2, 0x5a, sizeof(bmap2));
for (nbits = 0; nbits < 1024 - start; nbits += 8) {
bitmap_set(bmap1, start, nbits); bitmap_set(bmap1, start, nbits);
__bitmap_set(bmap2, start, nbits); __bitmap_set(bmap2, start, nbits);
if (!bitmap_equal(bmap1, bmap2, 1024)) if (!bitmap_equal(bmap1, bmap2, 1024)) {
printk("set not equal %d %d\n", start, nbits); printk("set not equal %d %d\n", start, nbits);
if (!__bitmap_equal(bmap1, bmap2, 1024)) failed_tests++;
}
if (!__bitmap_equal(bmap1, bmap2, 1024)) {
printk("set not __equal %d %d\n", start, nbits); printk("set not __equal %d %d\n", start, nbits);
failed_tests++;
}
bitmap_clear(bmap1, start, nbits); bitmap_clear(bmap1, start, nbits);
__bitmap_clear(bmap2, start, nbits); __bitmap_clear(bmap2, start, nbits);
if (!bitmap_equal(bmap1, bmap2, 1024)) if (!bitmap_equal(bmap1, bmap2, 1024)) {
printk("clear not equal %d %d\n", start, nbits); printk("clear not equal %d %d\n", start, nbits);
if (!__bitmap_equal(bmap1, bmap2, 1024)) failed_tests++;
}
if (!__bitmap_equal(bmap1, bmap2, 1024)) {
printk("clear not __equal %d %d\n", start, printk("clear not __equal %d %d\n", start,
nbits); nbits);
failed_tests++;
}
} }
} }
} }
......
...@@ -636,6 +636,7 @@ config DEFERRED_STRUCT_PAGE_INIT ...@@ -636,6 +636,7 @@ config DEFERRED_STRUCT_PAGE_INIT
default n default n
depends on NO_BOOTMEM depends on NO_BOOTMEM
depends on !FLATMEM depends on !FLATMEM
depends on !NEED_PER_CPU_KM
help help
Ordinarily all struct pages are initialised during early boot in a Ordinarily all struct pages are initialised during early boot in a
single thread. On very large machines this can take a considerable single thread. On very large machines this can take a considerable
......
...@@ -6,8 +6,9 @@ ...@@ -6,8 +6,9 @@
#include <stdbool.h> #include <stdbool.h>
#define spinlock_t pthread_mutex_t #define spinlock_t pthread_mutex_t
#define DEFINE_SPINLOCK(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER; #define DEFINE_SPINLOCK(x) pthread_mutex_t x = PTHREAD_MUTEX_INITIALIZER
#define __SPIN_LOCK_UNLOCKED(x) (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER #define __SPIN_LOCK_UNLOCKED(x) (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER
#define spin_lock_init(x) pthread_mutex_init(x, NULL)
#define spin_lock_irqsave(x, f) (void)f, pthread_mutex_lock(x) #define spin_lock_irqsave(x, f) (void)f, pthread_mutex_lock(x)
#define spin_unlock_irqrestore(x, f) (void)f, pthread_mutex_unlock(x) #define spin_unlock_irqrestore(x, f) (void)f, pthread_mutex_unlock(x)
......
...@@ -17,7 +17,7 @@ ifeq ($(BUILD), 32) ...@@ -17,7 +17,7 @@ ifeq ($(BUILD), 32)
LDFLAGS += -m32 LDFLAGS += -m32
endif endif
targets: mapshift $(TARGETS) targets: generated/map-shift.h $(TARGETS)
main: $(OFILES) main: $(OFILES)
...@@ -42,9 +42,7 @@ radix-tree.c: ../../../lib/radix-tree.c ...@@ -42,9 +42,7 @@ radix-tree.c: ../../../lib/radix-tree.c
idr.c: ../../../lib/idr.c idr.c: ../../../lib/idr.c
sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@ sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@
.PHONY: mapshift generated/map-shift.h:
mapshift:
@if ! grep -qws $(SHIFT) generated/map-shift.h; then \ @if ! grep -qws $(SHIFT) generated/map-shift.h; then \
echo "#define RADIX_TREE_MAP_SHIFT $(SHIFT)" > \ echo "#define RADIX_TREE_MAP_SHIFT $(SHIFT)" > \
generated/map-shift.h; \ generated/map-shift.h; \
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/radix-tree.h> #include <linux/radix-tree.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <pthread.h>
#include "test.h" #include "test.h"
...@@ -624,6 +625,67 @@ static void multiorder_account(void) ...@@ -624,6 +625,67 @@ static void multiorder_account(void)
item_kill_tree(&tree); item_kill_tree(&tree);
} }
bool stop_iteration = false;
static void *creator_func(void *ptr)
{
/* 'order' is set up to ensure we have sibling entries */
unsigned int order = RADIX_TREE_MAP_SHIFT - 1;
struct radix_tree_root *tree = ptr;
int i;
for (i = 0; i < 10000; i++) {
item_insert_order(tree, 0, order);
item_delete_rcu(tree, 0);
}
stop_iteration = true;
return NULL;
}
static void *iterator_func(void *ptr)
{
struct radix_tree_root *tree = ptr;
struct radix_tree_iter iter;
struct item *item;
void **slot;
while (!stop_iteration) {
rcu_read_lock();
radix_tree_for_each_slot(slot, tree, &iter, 0) {
item = radix_tree_deref_slot(slot);
if (!item)
continue;
if (radix_tree_deref_retry(item)) {
slot = radix_tree_iter_retry(&iter);
continue;
}
item_sanity(item, iter.index);
}
rcu_read_unlock();
}
return NULL;
}
static void multiorder_iteration_race(void)
{
const int num_threads = sysconf(_SC_NPROCESSORS_ONLN);
pthread_t worker_thread[num_threads];
RADIX_TREE(tree, GFP_KERNEL);
int i;
pthread_create(&worker_thread[0], NULL, &creator_func, &tree);
for (i = 1; i < num_threads; i++)
pthread_create(&worker_thread[i], NULL, &iterator_func, &tree);
for (i = 0; i < num_threads; i++)
pthread_join(worker_thread[i], NULL);
item_kill_tree(&tree);
}
void multiorder_checks(void) void multiorder_checks(void)
{ {
int i; int i;
...@@ -644,6 +706,7 @@ void multiorder_checks(void) ...@@ -644,6 +706,7 @@ void multiorder_checks(void)
multiorder_join(); multiorder_join();
multiorder_split(); multiorder_split();
multiorder_account(); multiorder_account();
multiorder_iteration_race();
radix_tree_cpu_dead(0); radix_tree_cpu_dead(0);
} }
......
...@@ -75,6 +75,25 @@ int item_delete(struct radix_tree_root *root, unsigned long index) ...@@ -75,6 +75,25 @@ int item_delete(struct radix_tree_root *root, unsigned long index)
return 0; return 0;
} }
static void item_free_rcu(struct rcu_head *head)
{
struct item *item = container_of(head, struct item, rcu_head);
free(item);
}
int item_delete_rcu(struct radix_tree_root *root, unsigned long index)
{
struct item *item = radix_tree_delete(root, index);
if (item) {
item_sanity(item, index);
call_rcu(&item->rcu_head, item_free_rcu);
return 1;
}
return 0;
}
void item_check_present(struct radix_tree_root *root, unsigned long index) void item_check_present(struct radix_tree_root *root, unsigned long index)
{ {
struct item *item; struct item *item;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
struct item { struct item {
struct rcu_head rcu_head;
unsigned long index; unsigned long index;
unsigned int order; unsigned int order;
}; };
...@@ -12,9 +13,11 @@ struct item { ...@@ -12,9 +13,11 @@ struct item {
struct item *item_create(unsigned long index, unsigned int order); struct item *item_create(unsigned long index, unsigned int order);
int __item_insert(struct radix_tree_root *root, struct item *item); int __item_insert(struct radix_tree_root *root, struct item *item);
int item_insert(struct radix_tree_root *root, unsigned long index); int item_insert(struct radix_tree_root *root, unsigned long index);
void item_sanity(struct item *item, unsigned long index);
int item_insert_order(struct radix_tree_root *root, unsigned long index, int item_insert_order(struct radix_tree_root *root, unsigned long index,
unsigned order); unsigned order);
int item_delete(struct radix_tree_root *root, unsigned long index); int item_delete(struct radix_tree_root *root, unsigned long index);
int item_delete_rcu(struct radix_tree_root *root, unsigned long index);
struct item *item_lookup(struct radix_tree_root *root, unsigned long index); struct item *item_lookup(struct radix_tree_root *root, unsigned long index);
void item_check_present(struct radix_tree_root *root, unsigned long index); void item_check_present(struct radix_tree_root *root, unsigned long index);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment