Commit 41531c8f5f05aba5ec645d9770557eedbf75b422
1 parent
2e34bde185
Exists in
master
and in
4 other branches
dma-debug: add a check dma memory leaks
Impact: allow architectures to monitor busses for dma mem leakage This patch adds checking code to detect if a device has pending DMA operations when it is about to be unbound from its device driver. Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Showing 2 changed files with 62 additions and 0 deletions Side-by-side Diff
include/linux/dma-debug.h
... | ... | @@ -24,9 +24,12 @@ |
24 | 24 | |
25 | 25 | struct device; |
26 | 26 | struct scatterlist; |
27 | +struct bus_type; | |
27 | 28 | |
28 | 29 | #ifdef CONFIG_DMA_API_DEBUG |
29 | 30 | |
31 | +extern void dma_debug_add_bus(struct bus_type *bus); | |
32 | + | |
30 | 33 | extern void dma_debug_init(u32 num_entries); |
31 | 34 | |
32 | 35 | extern void debug_dma_map_page(struct device *dev, struct page *page, |
... | ... | @@ -79,6 +82,10 @@ |
79 | 82 | extern void debug_dma_dump_mappings(struct device *dev); |
80 | 83 | |
81 | 84 | #else /* CONFIG_DMA_API_DEBUG */ |
85 | + | |
86 | +void dma_debug_add_bus(struct bus_type *bus) | |
87 | +{ | |
88 | +} | |
82 | 89 | |
83 | 90 | static inline void dma_debug_init(u32 num_entries) |
84 | 91 | { |
lib/dma-debug.c
... | ... | @@ -400,6 +400,61 @@ |
400 | 400 | return -ENOMEM; |
401 | 401 | } |
402 | 402 | |
403 | +static int device_dma_allocations(struct device *dev) | |
404 | +{ | |
405 | + struct dma_debug_entry *entry; | |
406 | + unsigned long flags; | |
407 | + int count = 0, i; | |
408 | + | |
409 | + for (i = 0; i < HASH_SIZE; ++i) { | |
410 | + spin_lock_irqsave(&dma_entry_hash[i].lock, flags); | |
411 | + list_for_each_entry(entry, &dma_entry_hash[i].list, list) { | |
412 | + if (entry->dev == dev) | |
413 | + count += 1; | |
414 | + } | |
415 | + spin_unlock_irqrestore(&dma_entry_hash[i].lock, flags); | |
416 | + } | |
417 | + | |
418 | + return count; | |
419 | +} | |
420 | + | |
421 | +static int dma_debug_device_change(struct notifier_block *nb, | |
422 | + unsigned long action, void *data) | |
423 | +{ | |
424 | + struct device *dev = data; | |
425 | + int count; | |
426 | + | |
427 | + | |
428 | + switch (action) { | |
429 | + case BUS_NOTIFY_UNBIND_DRIVER: | |
430 | + count = device_dma_allocations(dev); | |
431 | + if (count == 0) | |
432 | + break; | |
433 | + err_printk(dev, NULL, "DMA-API: device driver has pending " | |
434 | + "DMA allocations while released from device " | |
435 | + "[count=%d]\n", count); | |
436 | + break; | |
437 | + default: | |
438 | + break; | |
439 | + } | |
440 | + | |
441 | + return 0; | |
442 | +} | |
443 | + | |
444 | +void dma_debug_add_bus(struct bus_type *bus) | |
445 | +{ | |
446 | + struct notifier_block *nb; | |
447 | + | |
448 | + nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL); | |
449 | + if (nb == NULL) { | |
450 | + printk(KERN_ERR "dma_debug_add_bus: out of memory\n"); | |
451 | + return; | |
452 | + } | |
453 | + | |
454 | + nb->notifier_call = dma_debug_device_change; | |
455 | + | |
456 | + bus_register_notifier(bus, nb); | |
457 | +} | |
403 | 458 | |
404 | 459 | /* |
405 | 460 | * Let the architectures decide how many entries should be preallocated. |