Commit 8a6fc708b9bb48a79a385bdc2be0959ee2ab788d

Authored by Joerg Roedel
1 parent 2e507d849f

dma-debug: add debugfs file for driver filter

This patch adds the dma-api/driver_filter file to debugfs. The root user
can write a driver name into this file to see only dma-api errors for
that particular driver in the kernel log. Writing an empty string to
that file disables the driver filter.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>

Showing 1 changed file with 101 additions and 1 deletions Side-by-side Diff

... ... @@ -23,9 +23,11 @@
23 23 #include <linux/dma-debug.h>
24 24 #include <linux/spinlock.h>
25 25 #include <linux/debugfs.h>
  26 +#include <linux/uaccess.h>
26 27 #include <linux/device.h>
27 28 #include <linux/types.h>
28 29 #include <linux/sched.h>
  30 +#include <linux/ctype.h>
29 31 #include <linux/list.h>
30 32 #include <linux/slab.h>
31 33  
... ... @@ -98,6 +100,7 @@
98 100 static struct dentry *show_num_errors_dent __read_mostly;
99 101 static struct dentry *num_free_entries_dent __read_mostly;
100 102 static struct dentry *min_free_entries_dent __read_mostly;
  103 +static struct dentry *filter_dent __read_mostly;
101 104  
102 105 /* per-driver filter related state */
103 106  
... ... @@ -160,7 +163,8 @@
160 163 read_lock_irqsave(&driver_name_lock, flags);
161 164  
162 165 if (drv->name &&
163   - strncmp(current_driver_name, drv->name, 63) == 0) {
  166 + strncmp(current_driver_name, drv->name,
  167 + NAME_MAX_LEN-1) == 0) {
164 168 current_driver = drv;
165 169 ret = true;
166 170 }
... ... @@ -454,6 +458,97 @@
454 458 return -ENOMEM;
455 459 }
456 460  
  461 +static ssize_t filter_read(struct file *file, char __user *user_buf,
  462 + size_t count, loff_t *ppos)
  463 +{
  464 + unsigned long flags;
  465 + char buf[NAME_MAX_LEN + 1];
  466 + int len;
  467 +
  468 + if (!current_driver_name[0])
  469 + return 0;
  470 +
  471 + /*
  472 + * We can't copy to userspace directly because current_driver_name can
  473 + * only be read under the driver_name_lock with irqs disabled. So
  474 + * create a temporary copy first.
  475 + */
  476 + read_lock_irqsave(&driver_name_lock, flags);
  477 + len = scnprintf(buf, NAME_MAX_LEN + 1, "%s\n", current_driver_name);
  478 + read_unlock_irqrestore(&driver_name_lock, flags);
  479 +
  480 + return simple_read_from_buffer(user_buf, count, ppos, buf, len);
  481 +}
  482 +
  483 +static ssize_t filter_write(struct file *file, const char __user *userbuf,
  484 + size_t count, loff_t *ppos)
  485 +{
  486 + unsigned long flags;
  487 + char buf[NAME_MAX_LEN];
  488 + size_t len = NAME_MAX_LEN - 1;
  489 + int i;
  490 +
  491 + /*
  492 + * We can't copy from userspace directly. Access to
  493 + * current_driver_name is protected with a write_lock with irqs
  494 + * disabled. Since copy_from_user can fault and may sleep we
  495 + * need to copy to temporary buffer first
  496 + */
  497 + len = min(count, len);
  498 + if (copy_from_user(buf, userbuf, len))
  499 + return -EFAULT;
  500 +
  501 + buf[len] = 0;
  502 +
  503 + write_lock_irqsave(&driver_name_lock, flags);
  504 +
  505 + /* Now handle the string we got from userspace very carefully.
  506 + * The rules are:
  507 + * - only use the first token we got
  508 + * - token delimiter is everything looking like a space
  509 + * character (' ', '\n', '\t' ...)
  510 + *
  511 + */
  512 + if (!isalnum(buf[0])) {
  513 + /*
  514 + If the first character userspace gave us is not
  515 + * alphanumerical then assume the filter should be
  516 + * switched off.
  517 + */
  518 + if (current_driver_name[0])
  519 + printk(KERN_INFO "DMA-API: switching off dma-debug "
  520 + "driver filter\n");
  521 + current_driver_name[0] = 0;
  522 + current_driver = NULL;
  523 + goto out_unlock;
  524 + }
  525 +
  526 + /*
  527 + * Now parse out the first token and use it as the name for the
  528 + * driver to filter for.
  529 + */
  530 + for (i = 0; i < NAME_MAX_LEN; ++i) {
  531 + current_driver_name[i] = buf[i];
  532 + if (isspace(buf[i]) || buf[i] == ' ' || buf[i] == 0)
  533 + break;
  534 + }
  535 + current_driver_name[i] = 0;
  536 + current_driver = NULL;
  537 +
  538 + printk(KERN_INFO "DMA-API: enable driver filter for driver [%s]\n",
  539 + current_driver_name);
  540 +
  541 +out_unlock:
  542 + write_unlock_irqrestore(&driver_name_lock, flags);
  543 +
  544 + return count;
  545 +}
  546 +
  547 +const struct file_operations filter_fops = {
  548 + .read = filter_read,
  549 + .write = filter_write,
  550 +};
  551 +
457 552 static int dma_debug_fs_init(void)
458 553 {
459 554 dma_debug_dent = debugfs_create_dir("dma-api", NULL);
... ... @@ -495,6 +590,11 @@
495 590 dma_debug_dent,
496 591 &min_free_entries);
497 592 if (!min_free_entries_dent)
  593 + goto out_err;
  594 +
  595 + filter_dent = debugfs_create_file("driver_filter", 0644,
  596 + dma_debug_dent, NULL, &filter_fops);
  597 + if (!filter_dent)
498 598 goto out_err;
499 599  
500 600 return 0;