tcp: enforce tcp_min_snd_mss in tcp_mtu_probing()
[pandora-kernel.git] / mm / kmemleak.c
index f3b2a00..cbae846 100644 (file)
@@ -192,6 +192,8 @@ static struct kmem_cache *scan_area_cache;
 
 /* set if tracing memory operations is enabled */
 static atomic_t kmemleak_enabled = ATOMIC_INIT(0);
+/* same as above but only for the kmemleak_free() callback */
+static int kmemleak_free_enabled;
 /* set in the late_initcall if there were no errors */
 static atomic_t kmemleak_initialized = ATOMIC_INIT(0);
 /* enables or disables early logging of the memory operations */
@@ -744,7 +746,9 @@ static void add_scan_area(unsigned long ptr, size_t size, gfp_t gfp)
        }
 
        spin_lock_irqsave(&object->lock, flags);
-       if (ptr + size > object->pointer + object->size) {
+       if (size == SIZE_MAX) {
+               size = object->pointer + object->size - ptr;
+       } else if (ptr + size > object->pointer + object->size) {
                kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr);
                dump_object_info(object);
                kmem_cache_free(scan_area_cache, area);
@@ -883,7 +887,7 @@ void __ref kmemleak_free(const void *ptr)
 {
        pr_debug("%s(0x%p)\n", __func__, ptr);
 
-       if (atomic_read(&kmemleak_enabled) && ptr && !IS_ERR(ptr))
+       if (kmemleak_free_enabled && ptr && !IS_ERR(ptr))
                delete_object_full((unsigned long)ptr);
        else if (atomic_read(&kmemleak_early_log))
                log_early(KMEMLEAK_FREE, ptr, 0, 0);
@@ -1612,6 +1616,13 @@ static void kmemleak_do_cleanup(struct work_struct *work)
        mutex_lock(&scan_mutex);
        stop_scan_thread();
 
+       /*
+        * Once the scan thread has stopped, it is safe to no longer track
+        * object freeing. Ordering of the scan thread stopping and the memory
+        * accesses below is guaranteed by the kthread_stop() function.
+        */
+       kmemleak_free_enabled = 0;
+
        rcu_read_lock();
        list_for_each_entry_rcu(object, &object_list, object_list)
                delete_object_full(object->pointer);
@@ -1638,6 +1649,8 @@ static void kmemleak_disable(void)
        /* check whether it is too early for a kernel thread */
        if (atomic_read(&kmemleak_initialized))
                schedule_work(&cleanup_work);
+       else
+               kmemleak_free_enabled = 0;
 
        pr_info("Kernel memory leak detector disabled\n");
 }
@@ -1686,6 +1699,7 @@ void __init kmemleak_init(void)
        if (!atomic_read(&kmemleak_error)) {
                atomic_set(&kmemleak_enabled, 1);
                atomic_set(&kmemleak_early_log, 0);
+               kmemleak_free_enabled = 1;
        }
        local_irq_restore(flags);