Commit 41531c8f5f05aba5ec645d9770557eedbf75b422

Authored by Joerg Roedel
1 parent 2e34bde185

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 {
... ... @@ -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.