aboutsummaryrefslogtreecommitdiff
path: root/mm/kmemleak.c
diff options
context:
space:
mode:
authorKevin Hilman <khilman@linaro.org>2015-07-22 08:17:15 -0700
committerKevin Hilman <khilman@linaro.org>2015-07-22 08:17:15 -0700
commit2447e09699cca5db52f86182f163f3a25d1089ab (patch)
treee16730dba489e5ea0f16737597525724daa5c770 /mm/kmemleak.c
parent5a277b6839c4ef6c6ccacff49b64f302598264bf (diff)
parentc8bde72f9af412de57f0ceae218d648640118b0b (diff)
Merge branch 'linux-4.1.y' of git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable into linux-linaro-lsk-v4.1lsk-v4.1-15.07
* 'linux-4.1.y' of git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable: (126 commits) Linux 4.1.3 Input: pixcir_i2c_ts - fix receive error of/pci: Fix pci_address_to_pio() conversion of CPU address to I/O port PCI: pciehp: Wait for hotplug command completion where necessary PCI: Add pci_bus_addr_t PCI: Propagate the "ignore hotplug" setting to parent mtd: dc21285: use raw spinlock functions for nw_gpio_lock mtd: fix: avoid race condition when accessing mtd->usecount leds / PM: fix hibernation on arm when gpio-led used with CPU led trigger video: mxsfb: Make sure axi clock is enabled when accessing registers genirq: devres: Fix testing return value of request_any_context_irq() IB/srp: Fix reconnection failure handling IB/srp: Fix connection state tracking IB/srp: Fix a connection setup race IB/srp: Remove an extraneous scsi_host_put() from an error path scsi_transport_srp: Fix a race condition scsi_transport_srp: Introduce srp_wait_for_queuecommand() spi: pl022: Specify 'num-cs' property as required in devicetree binding spi: orion: Fix maximum baud rates for Armada 370/XP spi: fix race freeing dummy_tx/rx before it is unmapped ...
Diffstat (limited to 'mm/kmemleak.c')
-rw-r--r--mm/kmemleak.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index f0fe4f2c1fa7..3716cdb8ba42 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -195,6 +195,8 @@ static struct kmem_cache *scan_area_cache;
/* set if tracing memory operations is enabled */
static int kmemleak_enabled;
+/* 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 int kmemleak_initialized;
/* enables or disables early logging of the memory operations */
@@ -907,12 +909,13 @@ EXPORT_SYMBOL_GPL(kmemleak_alloc);
* kmemleak_alloc_percpu - register a newly allocated __percpu object
* @ptr: __percpu pointer to beginning of the object
* @size: size of the object
+ * @gfp: flags used for kmemleak internal memory allocations
*
* This function is called from the kernel percpu allocator when a new object
- * (memory block) is allocated (alloc_percpu). It assumes GFP_KERNEL
- * allocation.
+ * (memory block) is allocated (alloc_percpu).
*/
-void __ref kmemleak_alloc_percpu(const void __percpu *ptr, size_t size)
+void __ref kmemleak_alloc_percpu(const void __percpu *ptr, size_t size,
+ gfp_t gfp)
{
unsigned int cpu;
@@ -925,7 +928,7 @@ void __ref kmemleak_alloc_percpu(const void __percpu *ptr, size_t size)
if (kmemleak_enabled && ptr && !IS_ERR(ptr))
for_each_possible_cpu(cpu)
create_object((unsigned long)per_cpu_ptr(ptr, cpu),
- size, 0, GFP_KERNEL);
+ size, 0, gfp);
else if (kmemleak_early_log)
log_early(KMEMLEAK_ALLOC_PERCPU, ptr, size, 0);
}
@@ -942,7 +945,7 @@ void __ref kmemleak_free(const void *ptr)
{
pr_debug("%s(0x%p)\n", __func__, ptr);
- if (kmemleak_enabled && ptr && !IS_ERR(ptr))
+ if (kmemleak_free_enabled && ptr && !IS_ERR(ptr))
delete_object_full((unsigned long)ptr);
else if (kmemleak_early_log)
log_early(KMEMLEAK_FREE, ptr, 0, 0);
@@ -982,7 +985,7 @@ void __ref kmemleak_free_percpu(const void __percpu *ptr)
pr_debug("%s(0x%p)\n", __func__, ptr);
- if (kmemleak_enabled && ptr && !IS_ERR(ptr))
+ if (kmemleak_free_enabled && ptr && !IS_ERR(ptr))
for_each_possible_cpu(cpu)
delete_object_full((unsigned long)per_cpu_ptr(ptr,
cpu));
@@ -1750,6 +1753,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;
+
if (!kmemleak_found_leaks)
__kmemleak_do_cleanup();
else
@@ -1776,6 +1786,8 @@ static void kmemleak_disable(void)
/* check whether it is too early for a kernel thread */
if (kmemleak_initialized)
schedule_work(&cleanup_work);
+ else
+ kmemleak_free_enabled = 0;
pr_info("Kernel memory leak detector disabled\n");
}
@@ -1840,8 +1852,10 @@ void __init kmemleak_init(void)
if (kmemleak_error) {
local_irq_restore(flags);
return;
- } else
+ } else {
kmemleak_enabled = 1;
+ kmemleak_free_enabled = 1;
+ }
local_irq_restore(flags);
/*