Commit f03683b8 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'core-urgent-for-linus' of...

Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  slab, lockdep: Annotate the locks before using them
  lockdep: Clear whole lockdep_map on initialization
  slab, lockdep: Annotate slab -> rcu -> debug_object -> slab
  lockdep: Fix up warning
  lockdep: Fix trace_hardirqs_on_caller()
  futex: Fix regression with read only mappings
parents 7f3bf7cd 30765b92
...@@ -218,6 +218,8 @@ static void drop_futex_key_refs(union futex_key *key) ...@@ -218,6 +218,8 @@ static void drop_futex_key_refs(union futex_key *key)
* @uaddr: virtual address of the futex * @uaddr: virtual address of the futex
* @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED * @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED
* @key: address where result is stored. * @key: address where result is stored.
* @rw: mapping needs to be read/write (values: VERIFY_READ,
* VERIFY_WRITE)
* *
* Returns a negative error code or 0 * Returns a negative error code or 0
* The key words are stored in *key on success. * The key words are stored in *key on success.
...@@ -229,12 +231,12 @@ static void drop_futex_key_refs(union futex_key *key) ...@@ -229,12 +231,12 @@ static void drop_futex_key_refs(union futex_key *key)
* lock_page() might sleep, the caller should not hold a spinlock. * lock_page() might sleep, the caller should not hold a spinlock.
*/ */
static int static int
get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw)
{ {
unsigned long address = (unsigned long)uaddr; unsigned long address = (unsigned long)uaddr;
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
struct page *page, *page_head; struct page *page, *page_head;
int err; int err, ro = 0;
/* /*
* The futex address must be "naturally" aligned. * The futex address must be "naturally" aligned.
...@@ -262,8 +264,18 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) ...@@ -262,8 +264,18 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
again: again:
err = get_user_pages_fast(address, 1, 1, &page); err = get_user_pages_fast(address, 1, 1, &page);
/*
* If write access is not required (eg. FUTEX_WAIT), try
* and get read-only access.
*/
if (err == -EFAULT && rw == VERIFY_READ) {
err = get_user_pages_fast(address, 1, 0, &page);
ro = 1;
}
if (err < 0) if (err < 0)
return err; return err;
else
err = 0;
#ifdef CONFIG_TRANSPARENT_HUGEPAGE #ifdef CONFIG_TRANSPARENT_HUGEPAGE
page_head = page; page_head = page;
...@@ -305,6 +317,13 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) ...@@ -305,6 +317,13 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
if (!page_head->mapping) { if (!page_head->mapping) {
unlock_page(page_head); unlock_page(page_head);
put_page(page_head); put_page(page_head);
/*
* ZERO_PAGE pages don't have a mapping. Avoid a busy loop
* trying to find one. RW mapping would have COW'd (and thus
* have a mapping) so this page is RO and won't ever change.
*/
if ((page_head == ZERO_PAGE(address)))
return -EFAULT;
goto again; goto again;
} }
...@@ -316,6 +335,15 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) ...@@ -316,6 +335,15 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
* the object not the particular process. * the object not the particular process.
*/ */
if (PageAnon(page_head)) { if (PageAnon(page_head)) {
/*
* A RO anonymous page will never change and thus doesn't make
* sense for futex operations.
*/
if (ro) {
err = -EFAULT;
goto out;
}
key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */ key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */
key->private.mm = mm; key->private.mm = mm;
key->private.address = address; key->private.address = address;
...@@ -327,9 +355,10 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key) ...@@ -327,9 +355,10 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key)
get_futex_key_refs(key); get_futex_key_refs(key);
out:
unlock_page(page_head); unlock_page(page_head);
put_page(page_head); put_page(page_head);
return 0; return err;
} }
static inline void put_futex_key(union futex_key *key) static inline void put_futex_key(union futex_key *key)
...@@ -940,7 +969,7 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset) ...@@ -940,7 +969,7 @@ futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)
if (!bitset) if (!bitset)
return -EINVAL; return -EINVAL;
ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key); ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_READ);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
...@@ -986,10 +1015,10 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2, ...@@ -986,10 +1015,10 @@ futex_wake_op(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2,
int ret, op_ret; int ret, op_ret;
retry: retry:
ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1); ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2); ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, VERIFY_WRITE);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out_put_key1; goto out_put_key1;
...@@ -1243,10 +1272,11 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags, ...@@ -1243,10 +1272,11 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
pi_state = NULL; pi_state = NULL;
} }
ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1); ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2); ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2,
requeue_pi ? VERIFY_WRITE : VERIFY_READ);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out_put_key1; goto out_put_key1;
...@@ -1790,7 +1820,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags, ...@@ -1790,7 +1820,7 @@ static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,
* while the syscall executes. * while the syscall executes.
*/ */
retry: retry:
ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key); ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, VERIFY_READ);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
return ret; return ret;
...@@ -1941,7 +1971,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags, int detect, ...@@ -1941,7 +1971,7 @@ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags, int detect,
} }
retry: retry:
ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key); ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key, VERIFY_WRITE);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
...@@ -2060,7 +2090,7 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags) ...@@ -2060,7 +2090,7 @@ static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags)
if ((uval & FUTEX_TID_MASK) != vpid) if ((uval & FUTEX_TID_MASK) != vpid)
return -EPERM; return -EPERM;
ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key); ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_WRITE);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
...@@ -2249,7 +2279,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags, ...@@ -2249,7 +2279,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
debug_rt_mutex_init_waiter(&rt_waiter); debug_rt_mutex_init_waiter(&rt_waiter);
rt_waiter.task = NULL; rt_waiter.task = NULL;
ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2); ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, VERIFY_WRITE);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out; goto out;
......
...@@ -2468,7 +2468,7 @@ mark_held_locks(struct task_struct *curr, enum mark_type mark) ...@@ -2468,7 +2468,7 @@ mark_held_locks(struct task_struct *curr, enum mark_type mark)
BUG_ON(usage_bit >= LOCK_USAGE_STATES); BUG_ON(usage_bit >= LOCK_USAGE_STATES);
if (hlock_class(hlock)->key == &__lockdep_no_validate__) if (hlock_class(hlock)->key == __lockdep_no_validate__.subkeys)
continue; continue;
if (!mark_lock(curr, hlock, usage_bit)) if (!mark_lock(curr, hlock, usage_bit))
...@@ -2485,23 +2485,9 @@ static void __trace_hardirqs_on_caller(unsigned long ip) ...@@ -2485,23 +2485,9 @@ static void __trace_hardirqs_on_caller(unsigned long ip)
{ {
struct task_struct *curr = current; struct task_struct *curr = current;
if (DEBUG_LOCKS_WARN_ON(unlikely(early_boot_irqs_disabled)))
return;
if (unlikely(curr->hardirqs_enabled)) {
/*
* Neither irq nor preemption are disabled here
* so this is racy by nature but losing one hit
* in a stat is not a big deal.
*/
__debug_atomic_inc(redundant_hardirqs_on);
return;
}
/* we'll do an OFF -> ON transition: */ /* we'll do an OFF -> ON transition: */
curr->hardirqs_enabled = 1; curr->hardirqs_enabled = 1;
if (DEBUG_LOCKS_WARN_ON(current->hardirq_context))
return;
/* /*
* We are going to turn hardirqs on, so set the * We are going to turn hardirqs on, so set the
* usage bit for all held locks: * usage bit for all held locks:
...@@ -2529,9 +2515,25 @@ void trace_hardirqs_on_caller(unsigned long ip) ...@@ -2529,9 +2515,25 @@ void trace_hardirqs_on_caller(unsigned long ip)
if (unlikely(!debug_locks || current->lockdep_recursion)) if (unlikely(!debug_locks || current->lockdep_recursion))
return; return;
if (unlikely(current->hardirqs_enabled)) {
/*
* Neither irq nor preemption are disabled here
* so this is racy by nature but losing one hit
* in a stat is not a big deal.
*/
__debug_atomic_inc(redundant_hardirqs_on);
return;
}
if (DEBUG_LOCKS_WARN_ON(!irqs_disabled())) if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
return; return;
if (DEBUG_LOCKS_WARN_ON(unlikely(early_boot_irqs_disabled)))
return;
if (DEBUG_LOCKS_WARN_ON(current->hardirq_context))
return;
current->lockdep_recursion = 1; current->lockdep_recursion = 1;
__trace_hardirqs_on_caller(ip); __trace_hardirqs_on_caller(ip);
current->lockdep_recursion = 0; current->lockdep_recursion = 0;
...@@ -2872,10 +2874,7 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this, ...@@ -2872,10 +2874,7 @@ static int mark_lock(struct task_struct *curr, struct held_lock *this,
void lockdep_init_map(struct lockdep_map *lock, const char *name, void lockdep_init_map(struct lockdep_map *lock, const char *name,
struct lock_class_key *key, int subclass) struct lock_class_key *key, int subclass)
{ {
int i; memset(lock, 0, sizeof(*lock));
for (i = 0; i < NR_LOCKDEP_CACHING_CLASSES; i++)
lock->class_cache[i] = NULL;
#ifdef CONFIG_LOCK_STAT #ifdef CONFIG_LOCK_STAT
lock->cpu = raw_smp_processor_id(); lock->cpu = raw_smp_processor_id();
......
...@@ -622,22 +622,22 @@ int slab_is_available(void) ...@@ -622,22 +622,22 @@ int slab_is_available(void)
static struct lock_class_key on_slab_l3_key; static struct lock_class_key on_slab_l3_key;
static struct lock_class_key on_slab_alc_key; static struct lock_class_key on_slab_alc_key;
static void init_node_lock_keys(int q) static struct lock_class_key debugobj_l3_key;
{ static struct lock_class_key debugobj_alc_key;
struct cache_sizes *s = malloc_sizes;
if (g_cpucache_up != FULL)
return;
for (s = malloc_sizes; s->cs_size != ULONG_MAX; s++) { static void slab_set_lock_classes(struct kmem_cache *cachep,
struct lock_class_key *l3_key, struct lock_class_key *alc_key,
int q)
{
struct array_cache **alc; struct array_cache **alc;
struct kmem_list3 *l3; struct kmem_list3 *l3;
int r; int r;
l3 = s->cs_cachep->nodelists[q]; l3 = cachep->nodelists[q];
if (!l3 || OFF_SLAB(s->cs_cachep)) if (!l3)
continue; return;
lockdep_set_class(&l3->list_lock, &on_slab_l3_key);
lockdep_set_class(&l3->list_lock, l3_key);
alc = l3->alien; alc = l3->alien;
/* /*
* FIXME: This check for BAD_ALIEN_MAGIC * FIXME: This check for BAD_ALIEN_MAGIC
...@@ -647,12 +647,42 @@ static void init_node_lock_keys(int q) ...@@ -647,12 +647,42 @@ static void init_node_lock_keys(int q)
* for alloc_alien_cache, * for alloc_alien_cache,
*/ */
if (!alc || (unsigned long)alc == BAD_ALIEN_MAGIC) if (!alc || (unsigned long)alc == BAD_ALIEN_MAGIC)
continue; return;
for_each_node(r) { for_each_node(r) {
if (alc[r]) if (alc[r])
lockdep_set_class(&alc[r]->lock, lockdep_set_class(&alc[r]->lock, alc_key);
&on_slab_alc_key);
} }
}
static void slab_set_debugobj_lock_classes_node(struct kmem_cache *cachep, int node)
{
slab_set_lock_classes(cachep, &debugobj_l3_key, &debugobj_alc_key, node);
}
static void slab_set_debugobj_lock_classes(struct kmem_cache *cachep)
{
int node;
for_each_online_node(node)
slab_set_debugobj_lock_classes_node(cachep, node);
}
static void init_node_lock_keys(int q)
{
struct cache_sizes *s = malloc_sizes;
if (g_cpucache_up != FULL)
return;
for (s = malloc_sizes; s->cs_size != ULONG_MAX; s++) {
struct kmem_list3 *l3;
l3 = s->cs_cachep->nodelists[q];
if (!l3 || OFF_SLAB(s->cs_cachep))
continue;
slab_set_lock_classes(s->cs_cachep, &on_slab_l3_key,
&on_slab_alc_key, q);
} }
} }
...@@ -671,6 +701,14 @@ static void init_node_lock_keys(int q) ...@@ -671,6 +701,14 @@ static void init_node_lock_keys(int q)
static inline void init_lock_keys(void) static inline void init_lock_keys(void)
{ {
} }
static void slab_set_debugobj_lock_classes_node(struct kmem_cache *cachep, int node)
{
}
static void slab_set_debugobj_lock_classes(struct kmem_cache *cachep)
{
}
#endif #endif
/* /*
...@@ -1264,6 +1302,8 @@ static int __cpuinit cpuup_prepare(long cpu) ...@@ -1264,6 +1302,8 @@ static int __cpuinit cpuup_prepare(long cpu)
spin_unlock_irq(&l3->list_lock); spin_unlock_irq(&l3->list_lock);
kfree(shared); kfree(shared);
free_alien_cache(alien); free_alien_cache(alien);
if (cachep->flags & SLAB_DEBUG_OBJECTS)
slab_set_debugobj_lock_classes_node(cachep, node);
} }
init_node_lock_keys(node); init_node_lock_keys(node);
...@@ -1626,6 +1666,9 @@ void __init kmem_cache_init_late(void) ...@@ -1626,6 +1666,9 @@ void __init kmem_cache_init_late(void)
{ {
struct kmem_cache *cachep; struct kmem_cache *cachep;
/* Annotate slab for lockdep -- annotate the malloc caches */
init_lock_keys();
/* 6) resize the head arrays to their final sizes */ /* 6) resize the head arrays to their final sizes */
mutex_lock(&cache_chain_mutex); mutex_lock(&cache_chain_mutex);
list_for_each_entry(cachep, &cache_chain, next) list_for_each_entry(cachep, &cache_chain, next)
...@@ -1636,9 +1679,6 @@ void __init kmem_cache_init_late(void) ...@@ -1636,9 +1679,6 @@ void __init kmem_cache_init_late(void)
/* Done! */ /* Done! */
g_cpucache_up = FULL; g_cpucache_up = FULL;
/* Annotate slab for lockdep -- annotate the malloc caches */
init_lock_keys();
/* /*
* Register a cpu startup notifier callback that initializes * Register a cpu startup notifier callback that initializes
* cpu_cache_get for all new cpus * cpu_cache_get for all new cpus
...@@ -2426,6 +2466,16 @@ kmem_cache_create (const char *name, size_t size, size_t align, ...@@ -2426,6 +2466,16 @@ kmem_cache_create (const char *name, size_t size, size_t align,
goto oops; goto oops;
} }
if (flags & SLAB_DEBUG_OBJECTS) {
/*
* Would deadlock through slab_destroy()->call_rcu()->
* debug_object_activate()->kmem_cache_alloc().
*/
WARN_ON_ONCE(flags & SLAB_DESTROY_BY_RCU);
slab_set_debugobj_lock_classes(cachep);
}
/* cache setup completed, link it into the list */ /* cache setup completed, link it into the list */
list_add(&cachep->next, &cache_chain); list_add(&cachep->next, &cache_chain);
oops: oops:
......
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