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
This commit is contained in:
commit
f03683b8fb
3 changed files with 131 additions and 52 deletions
|
@ -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)
|
||||||
* 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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
* 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
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,
|
||||||
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();
|
||||||
|
|
92
mm/slab.c
92
mm/slab.c
|
@ -622,6 +622,51 @@ 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 struct lock_class_key debugobj_l3_key;
|
||||||
|
static struct lock_class_key debugobj_alc_key;
|
||||||
|
|
||||||
|
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 kmem_list3 *l3;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
l3 = cachep->nodelists[q];
|
||||||
|
if (!l3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lockdep_set_class(&l3->list_lock, l3_key);
|
||||||
|
alc = l3->alien;
|
||||||
|
/*
|
||||||
|
* FIXME: This check for BAD_ALIEN_MAGIC
|
||||||
|
* should go away when common slab code is taught to
|
||||||
|
* work even without alien caches.
|
||||||
|
* Currently, non NUMA code returns BAD_ALIEN_MAGIC
|
||||||
|
* for alloc_alien_cache,
|
||||||
|
*/
|
||||||
|
if (!alc || (unsigned long)alc == BAD_ALIEN_MAGIC)
|
||||||
|
return;
|
||||||
|
for_each_node(r) {
|
||||||
|
if (alc[r])
|
||||||
|
lockdep_set_class(&alc[r]->lock, 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)
|
static void init_node_lock_keys(int q)
|
||||||
{
|
{
|
||||||
struct cache_sizes *s = malloc_sizes;
|
struct cache_sizes *s = malloc_sizes;
|
||||||
|
@ -630,29 +675,14 @@ static void init_node_lock_keys(int q)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (s = malloc_sizes; s->cs_size != ULONG_MAX; s++) {
|
for (s = malloc_sizes; s->cs_size != ULONG_MAX; s++) {
|
||||||
struct array_cache **alc;
|
|
||||||
struct kmem_list3 *l3;
|
struct kmem_list3 *l3;
|
||||||
int r;
|
|
||||||
|
|
||||||
l3 = s->cs_cachep->nodelists[q];
|
l3 = s->cs_cachep->nodelists[q];
|
||||||
if (!l3 || OFF_SLAB(s->cs_cachep))
|
if (!l3 || OFF_SLAB(s->cs_cachep))
|
||||||
continue;
|
continue;
|
||||||
lockdep_set_class(&l3->list_lock, &on_slab_l3_key);
|
|
||||||
alc = l3->alien;
|
slab_set_lock_classes(s->cs_cachep, &on_slab_l3_key,
|
||||||
/*
|
&on_slab_alc_key, q);
|
||||||
* FIXME: This check for BAD_ALIEN_MAGIC
|
|
||||||
* should go away when common slab code is taught to
|
|
||||||
* work even without alien caches.
|
|
||||||
* Currently, non NUMA code returns BAD_ALIEN_MAGIC
|
|
||||||
* for alloc_alien_cache,
|
|
||||||
*/
|
|
||||||
if (!alc || (unsigned long)alc == BAD_ALIEN_MAGIC)
|
|
||||||
continue;
|
|
||||||
for_each_node(r) {
|
|
||||||
if (alc[r])
|
|
||||||
lockdep_set_class(&alc[r]->lock,
|
|
||||||
&on_slab_alc_key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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)
|
||||||
/* 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,
|
||||||
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:
|
||||||
|
|
Loading…
Reference in a new issue