All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] dma-debug: driver filter v2
@ 2009-06-02 14:36 Joerg Roedel
  2009-06-02 14:36 ` [PATCH 1/4] dma-debug: add variables and checks for driver filter Joerg Roedel
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Joerg Roedel @ 2009-06-02 14:36 UTC (permalink / raw)
  To: iommu, linux-kernel; +Cc: akpm

Hi,

this small patchset adds a new feature to dma-api debugging: a driver
filter. A driver developer can write the name of his driver to
dma-api/driver_filter and the kernel will then only print errors
produced by this driver. This is useful if other drivers in the system
also have bugs. In this case the driver developer can limit the bug
output to messages interesting for him.

	Joerg

Changes since v1:

	- addressed Andrews comments (used string functions were
	  appropriate and reduced inlining, added some more
	  comments)

diffstat:

 Documentation/DMA-API.txt           |   12 +++
 Documentation/kernel-parameters.txt |    7 ++
 lib/dma-debug.c                     |  167 ++++++++++++++++++++++++++++++++++-
 3 files changed, 185 insertions(+), 1 deletions(-)

shortlog:

Joerg Roedel (4):
      dma-debug: add variables and checks for driver filter
      dma-debug: add debugfs file for driver filter
      dma-debug: add dma_debug_driver kernel command line
      dma-debug: add documentation for the driver filter



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/4] dma-debug: add variables and checks for driver filter
  2009-06-02 14:36 [PATCH 0/4] dma-debug: driver filter v2 Joerg Roedel
@ 2009-06-02 14:36 ` Joerg Roedel
  2009-06-02 14:36 ` [PATCH 2/4] dma-debug: add debugfs file " Joerg Roedel
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Joerg Roedel @ 2009-06-02 14:36 UTC (permalink / raw)
  To: iommu, linux-kernel; +Cc: akpm, Joerg Roedel

This patch adds the state variables for the driver filter and a function
to check if the filter is enabled and matches to the current device. The
check is built into the err_printk function.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
 lib/dma-debug.c |   49 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 48 insertions(+), 1 deletions(-)

diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index cdd205d..c01f647 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -99,6 +99,15 @@ static struct dentry *show_num_errors_dent  __read_mostly;
 static struct dentry *num_free_entries_dent __read_mostly;
 static struct dentry *min_free_entries_dent __read_mostly;
 
+/* per-driver filter related state */
+
+#define NAME_MAX_LEN	64
+
+static char                  current_driver_name[NAME_MAX_LEN] __read_mostly;
+static struct device_driver *current_driver                    __read_mostly;
+
+static DEFINE_RWLOCK(driver_name_lock);
+
 static const char *type2name[4] = { "single", "page",
 				    "scather-gather", "coherent" };
 
@@ -128,9 +137,47 @@ static inline void dump_entry_trace(struct dma_debug_entry *entry)
 #endif
 }
 
+static bool driver_filter(struct device *dev)
+{
+	/* driver filter off */
+	if (likely(!current_driver_name[0]))
+		return true;
+
+	/* driver filter on and initialized */
+	if (current_driver && dev->driver == current_driver)
+		return true;
+
+	/* driver filter on but not yet initialized */
+	if (!current_driver && current_driver_name[0]) {
+		struct device_driver *drv = get_driver(dev->driver);
+		unsigned long flags;
+		bool ret = false;
+
+		if (!drv)
+			return false;
+
+		/* lock to protect against change of current_driver_name */
+		read_lock_irqsave(&driver_name_lock, flags);
+
+		if (drv->name &&
+		    strncmp(current_driver_name, drv->name, 63) == 0) {
+			current_driver = drv;
+			ret = true;
+		}
+
+		read_unlock_irqrestore(&driver_name_lock, flags);
+		put_driver(drv);
+
+		return ret;
+	}
+
+	return false;
+}
+
 #define err_printk(dev, entry, format, arg...) do {		\
 		error_count += 1;				\
-		if (show_all_errors || show_num_errors > 0) {	\
+		if (driver_filter(dev) &&			\
+		    (show_all_errors || show_num_errors > 0)) {	\
 			WARN(1, "%s %s: " format,		\
 			     dev_driver_string(dev),		\
 			     dev_name(dev) , ## arg);		\
-- 
1.6.3.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/4] dma-debug: add debugfs file for driver filter
  2009-06-02 14:36 [PATCH 0/4] dma-debug: driver filter v2 Joerg Roedel
  2009-06-02 14:36 ` [PATCH 1/4] dma-debug: add variables and checks for driver filter Joerg Roedel
@ 2009-06-02 14:36 ` Joerg Roedel
  2009-06-02 14:36 ` [PATCH 3/4] dma-debug: add dma_debug_driver kernel command line Joerg Roedel
  2009-06-02 14:36 ` [PATCH 4/4] dma-debug: add documentation for the driver filter Joerg Roedel
  3 siblings, 0 replies; 8+ messages in thread
From: Joerg Roedel @ 2009-06-02 14:36 UTC (permalink / raw)
  To: iommu, linux-kernel; +Cc: akpm, Joerg Roedel

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>
---
 lib/dma-debug.c |  102 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 101 insertions(+), 1 deletions(-)

diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index c01f647..c6330b1 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -23,9 +23,11 @@
 #include <linux/dma-debug.h>
 #include <linux/spinlock.h>
 #include <linux/debugfs.h>
+#include <linux/uaccess.h>
 #include <linux/device.h>
 #include <linux/types.h>
 #include <linux/sched.h>
+#include <linux/ctype.h>
 #include <linux/list.h>
 #include <linux/slab.h>
 
@@ -98,6 +100,7 @@ static struct dentry *show_all_errors_dent  __read_mostly;
 static struct dentry *show_num_errors_dent  __read_mostly;
 static struct dentry *num_free_entries_dent __read_mostly;
 static struct dentry *min_free_entries_dent __read_mostly;
+static struct dentry *filter_dent           __read_mostly;
 
 /* per-driver filter related state */
 
@@ -160,7 +163,8 @@ static bool driver_filter(struct device *dev)
 		read_lock_irqsave(&driver_name_lock, flags);
 
 		if (drv->name &&
-		    strncmp(current_driver_name, drv->name, 63) == 0) {
+		    strncmp(current_driver_name, drv->name,
+			    NAME_MAX_LEN-1) == 0) {
 			current_driver = drv;
 			ret = true;
 		}
@@ -454,6 +458,97 @@ out_err:
 	return -ENOMEM;
 }
 
+static ssize_t filter_read(struct file *file, char __user *user_buf,
+			   size_t count, loff_t *ppos)
+{
+	unsigned long flags;
+	char buf[NAME_MAX_LEN + 1];
+	int len;
+
+	if (!current_driver_name[0])
+		return 0;
+
+	/*
+	 * We can't copy to userspace directly because current_driver_name can
+	 * only be read under the driver_name_lock with irqs disabled. So
+	 * create a temporary copy first.
+	 */
+	read_lock_irqsave(&driver_name_lock, flags);
+	len = scnprintf(buf, NAME_MAX_LEN + 1, "%s\n", current_driver_name);
+	read_unlock_irqrestore(&driver_name_lock, flags);
+
+	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t filter_write(struct file *file, const char __user *userbuf,
+			    size_t count, loff_t *ppos)
+{
+	unsigned long flags;
+	char buf[NAME_MAX_LEN];
+	size_t len = NAME_MAX_LEN - 1;
+	int i;
+
+	/*
+	 * We can't copy from userspace directly. Access to
+	 * current_driver_name is protected with a write_lock with irqs
+	 * disabled. Since copy_from_user can fault and may sleep we
+	 * need to copy to temporary buffer first
+	 */
+	len = min(count, len);
+	if (copy_from_user(buf, userbuf, len))
+		return -EFAULT;
+
+	buf[len] = 0;
+
+	write_lock_irqsave(&driver_name_lock, flags);
+
+	/* Now handle the string we got from userspace very carefully.
+	 * The rules are:
+	 *         - only use the first token we got
+	 *         - token delimiter is everything looking like a space
+	 *           character (' ', '\n', '\t' ...)
+	 *
+	 */
+	if (!isalnum(buf[0])) {
+		/*
+		   If the first character userspace gave us is not
+		 * alphanumerical then assume the filter should be
+		 * switched off.
+		 */
+		if (current_driver_name[0])
+			printk(KERN_INFO "DMA-API: switching off dma-debug "
+					 "driver filter\n");
+		current_driver_name[0] = 0;
+		current_driver = NULL;
+		goto out_unlock;
+	}
+
+	/*
+	 * Now parse out the first token and use it as the name for the
+	 * driver to filter for.
+	 */
+	for (i = 0; i < NAME_MAX_LEN; ++i) {
+		current_driver_name[i] = buf[i];
+		if (isspace(buf[i]) || buf[i] == ' ' || buf[i] == 0)
+			break;
+	}
+	current_driver_name[i] = 0;
+	current_driver = NULL;
+
+	printk(KERN_INFO "DMA-API: enable driver filter for driver [%s]\n",
+	       current_driver_name);
+
+out_unlock:
+	write_unlock_irqrestore(&driver_name_lock, flags);
+
+	return count;
+}
+
+const struct file_operations filter_fops = {
+	.read  = filter_read,
+	.write = filter_write,
+};
+
 static int dma_debug_fs_init(void)
 {
 	dma_debug_dent = debugfs_create_dir("dma-api", NULL);
@@ -497,6 +592,11 @@ static int dma_debug_fs_init(void)
 	if (!min_free_entries_dent)
 		goto out_err;
 
+	filter_dent = debugfs_create_file("driver_filter", 0644,
+					  dma_debug_dent, NULL, &filter_fops);
+	if (!filter_dent)
+		goto out_err;
+
 	return 0;
 
 out_err:
-- 
1.6.3.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/4] dma-debug: add dma_debug_driver kernel command line
  2009-06-02 14:36 [PATCH 0/4] dma-debug: driver filter v2 Joerg Roedel
  2009-06-02 14:36 ` [PATCH 1/4] dma-debug: add variables and checks for driver filter Joerg Roedel
  2009-06-02 14:36 ` [PATCH 2/4] dma-debug: add debugfs file " Joerg Roedel
@ 2009-06-02 14:36 ` Joerg Roedel
  2009-06-02 14:36 ` [PATCH 4/4] dma-debug: add documentation for the driver filter Joerg Roedel
  3 siblings, 0 replies; 8+ messages in thread
From: Joerg Roedel @ 2009-06-02 14:36 UTC (permalink / raw)
  To: iommu, linux-kernel; +Cc: akpm, Joerg Roedel

This patch add the dma_debug_driver= boot parameter to enable the driver
filter for early boot.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
 Documentation/kernel-parameters.txt |    7 +++++++
 lib/dma-debug.c                     |   18 ++++++++++++++++++
 2 files changed, 25 insertions(+), 0 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index e87bdbf..b3f1314 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -646,6 +646,13 @@ and is between 256 and 4096 characters. It is defined in the file
 			DMA-API debugging code disables itself because the
 			architectural default is too low.
 
+	dma_debug_driver=<driver_name>
+			With this option the DMA-API debugging driver
+			filter feature can be enabled at boot time. Just
+			pass the driver to filter for as the parameter.
+			The filter can be disabled or changed to another
+			driver later using sysfs.
+
 	dscc4.setup=	[NET]
 
 	dtc3181e=	[HW,SCSI]
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index c6330b1..d0618aa 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -1109,3 +1109,21 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
 }
 EXPORT_SYMBOL(debug_dma_sync_sg_for_device);
 
+static int __init dma_debug_driver_setup(char *str)
+{
+	int i;
+
+	for (i = 0; i < NAME_MAX_LEN - 1; ++i, ++str) {
+		current_driver_name[i] = *str;
+		if (*str == 0)
+			break;
+	}
+
+	if (current_driver_name[0])
+		printk(KERN_INFO "DMA-API: enable driver filter for "
+				 "driver [%s]\n", current_driver_name);
+
+
+	return 1;
+}
+__setup("dma_debug_driver=", dma_debug_driver_setup);
-- 
1.6.3.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/4] dma-debug: add documentation for the driver filter
  2009-06-02 14:36 [PATCH 0/4] dma-debug: driver filter v2 Joerg Roedel
                   ` (2 preceding siblings ...)
  2009-06-02 14:36 ` [PATCH 3/4] dma-debug: add dma_debug_driver kernel command line Joerg Roedel
@ 2009-06-02 14:36 ` Joerg Roedel
  3 siblings, 0 replies; 8+ messages in thread
From: Joerg Roedel @ 2009-06-02 14:36 UTC (permalink / raw)
  To: iommu, linux-kernel; +Cc: akpm, Joerg Roedel

This patch adds the driver filter feature to the dma-debug
documentation.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
 Documentation/DMA-API.txt |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
index d9aa43d..25fb8bc 100644
--- a/Documentation/DMA-API.txt
+++ b/Documentation/DMA-API.txt
@@ -704,12 +704,24 @@ this directory the following files can currently be found:
 				The current number of free dma_debug_entries
 				in the allocator.
 
+	dma-api/driver-filter
+				You can write a name of a driver into this file
+				to limit the debug output to requests from that
+				particular driver. Write an empty string to
+				that file to disable the filter and see
+				all errors again.
+
 If you have this code compiled into your kernel it will be enabled by default.
 If you want to boot without the bookkeeping anyway you can provide
 'dma_debug=off' as a boot parameter. This will disable DMA-API debugging.
 Notice that you can not enable it again at runtime. You have to reboot to do
 so.
 
+If you want to see debug messages only for a special device driver you can
+specify the dma_debug_driver=<drivername> parameter. This will enable the
+driver filter at boot time. The debug code will only print errors for that
+driver afterwards. This filter can be disabled or changed later using debugfs.
+
 When the code disables itself at runtime this is most likely because it ran
 out of dma_debug_entries. These entries are preallocated at boot. The number
 of preallocated entries is defined per architecture. If it is too low for you
-- 
1.6.3.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/4] dma-debug: add variables and checks for driver filter
  2009-06-01 21:55   ` Andrew Morton
@ 2009-06-02  8:27     ` Joerg Roedel
  0 siblings, 0 replies; 8+ messages in thread
From: Joerg Roedel @ 2009-06-02  8:27 UTC (permalink / raw)
  To: Andrew Morton; +Cc: iommu, linux-kernel

On Mon, Jun 01, 2009 at 02:55:02PM -0700, Andrew Morton wrote:
> On Thu, 28 May 2009 17:19:28 +0200
> Joerg Roedel <joerg.roedel@amd.com> wrote:
> 
> > This patch adds the state variables for the driver filter and a function
> > to check if the filter is enabled and matches to the current device. The
> > check is built into the err_printk function.
> > 
> 
> The path by which lib/dma-debug.c patches get into mainline seems to
> be largely random.  Is it a dwmw2 tree?  An Ingo tree?  A Joerg tree? -mm?

When I addresses your comment I will repost and send it to Ingo later
on. He will send it upstream. At least thats the current plan :-)

Joerg

-- 
           | Advanced Micro Devices GmbH
 Operating | Karl-Hammerschmidt-Str. 34, 85609 Dornach bei München
 System    | 
 Research  | Geschäftsführer: Thomas M. McCoy, Giuliano Meroni
 Center    | Sitz: Dornach, Gemeinde Aschheim, Landkreis München
           | Registergericht München, HRB Nr. 43632


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/4] dma-debug: add variables and checks for driver filter
  2009-05-28 15:19 ` [PATCH 1/4] dma-debug: add variables and checks for " Joerg Roedel
@ 2009-06-01 21:55   ` Andrew Morton
  2009-06-02  8:27     ` Joerg Roedel
  0 siblings, 1 reply; 8+ messages in thread
From: Andrew Morton @ 2009-06-01 21:55 UTC (permalink / raw)
  To: Joerg Roedel; +Cc: iommu, linux-kernel, joerg.roedel

On Thu, 28 May 2009 17:19:28 +0200
Joerg Roedel <joerg.roedel@amd.com> wrote:

> This patch adds the state variables for the driver filter and a function
> to check if the filter is enabled and matches to the current device. The
> check is built into the err_printk function.
> 

The path by which lib/dma-debug.c patches get into mainline seems to
be largely random.  Is it a dwmw2 tree?  An Ingo tree?  A Joerg tree? -mm?


> @@ -128,9 +137,47 @@ static inline void dump_entry_trace(struct dma_debug_entry *entry)
>  #endif
>  }
>  
> +static inline bool driver_filter(struct device *dev)
> +{
> +	/* driver filter off */
> +	if (likely(!current_driver_name[0]))
> +		return true;
> +
> +	/* driver filter on and initialized */
> +	if (current_driver && dev->driver == current_driver)
> +		return true;
> +
> +	/* driver filter on but not yet initialized */
> +	if (!current_driver && current_driver_name[0]) {
> +		struct device_driver *drv = get_driver(dev->driver);
> +		unsigned long flags;
> +		bool ret = false;
> +
> +		if (!drv)
> +			return false;
> +
> +		/* lock to protect against change of current_driver_name */
> +		read_lock_irqsave(&driver_name_lock, flags);
> +
> +		if (drv->name &&
> +		    strncmp(current_driver_name, drv->name, 63) == 0) {
> +			current_driver = drv;
> +			ret = true;
> +		}
> +
> +		read_unlock_irqrestore(&driver_name_lock, flags);
> +		put_driver(drv);
> +
> +		return ret;
> +	}
> +
> +	return false;
> +}
> +
>  #define err_printk(dev, entry, format, arg...) do {		\
>  		error_count += 1;				\
> -		if (show_all_errors || show_num_errors > 0) {	\
> +		if (driver_filter(dev) &&			\
> +		    (show_all_errors || show_num_errors > 0)) {	\
>  			WARN(1, "%s %s: " format,		\
>  			     dev_driver_string(dev),		\
>  			     dev_name(dev) , ## arg);		\

The patch attempts to inline the very large driver_filter() into every
err_printk() callsite.  That's not at all desirable!


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/4] dma-debug: add variables and checks for driver filter
  2009-05-28 15:19 [PATCH 0/4] dma-debug: " Joerg Roedel
@ 2009-05-28 15:19 ` Joerg Roedel
  2009-06-01 21:55   ` Andrew Morton
  0 siblings, 1 reply; 8+ messages in thread
From: Joerg Roedel @ 2009-05-28 15:19 UTC (permalink / raw)
  To: iommu, linux-kernel; +Cc: Joerg Roedel

This patch adds the state variables for the driver filter and a function
to check if the filter is enabled and matches to the current device. The
check is built into the err_printk function.

Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
---
 lib/dma-debug.c |   49 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 48 insertions(+), 1 deletions(-)

diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index cdd205d..e953270 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -99,6 +99,15 @@ static struct dentry *show_num_errors_dent  __read_mostly;
 static struct dentry *num_free_entries_dent __read_mostly;
 static struct dentry *min_free_entries_dent __read_mostly;
 
+/* per-driver filter related state */
+
+#define NAME_MAX_LEN	64
+
+static char                  current_driver_name[NAME_MAX_LEN] __read_mostly;
+static struct device_driver *current_driver                    __read_mostly;
+
+static DEFINE_RWLOCK(driver_name_lock);
+
 static const char *type2name[4] = { "single", "page",
 				    "scather-gather", "coherent" };
 
@@ -128,9 +137,47 @@ static inline void dump_entry_trace(struct dma_debug_entry *entry)
 #endif
 }
 
+static inline bool driver_filter(struct device *dev)
+{
+	/* driver filter off */
+	if (likely(!current_driver_name[0]))
+		return true;
+
+	/* driver filter on and initialized */
+	if (current_driver && dev->driver == current_driver)
+		return true;
+
+	/* driver filter on but not yet initialized */
+	if (!current_driver && current_driver_name[0]) {
+		struct device_driver *drv = get_driver(dev->driver);
+		unsigned long flags;
+		bool ret = false;
+
+		if (!drv)
+			return false;
+
+		/* lock to protect against change of current_driver_name */
+		read_lock_irqsave(&driver_name_lock, flags);
+
+		if (drv->name &&
+		    strncmp(current_driver_name, drv->name, 63) == 0) {
+			current_driver = drv;
+			ret = true;
+		}
+
+		read_unlock_irqrestore(&driver_name_lock, flags);
+		put_driver(drv);
+
+		return ret;
+	}
+
+	return false;
+}
+
 #define err_printk(dev, entry, format, arg...) do {		\
 		error_count += 1;				\
-		if (show_all_errors || show_num_errors > 0) {	\
+		if (driver_filter(dev) &&			\
+		    (show_all_errors || show_num_errors > 0)) {	\
 			WARN(1, "%s %s: " format,		\
 			     dev_driver_string(dev),		\
 			     dev_name(dev) , ## arg);		\
-- 
1.6.3.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2009-06-02 14:38 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-06-02 14:36 [PATCH 0/4] dma-debug: driver filter v2 Joerg Roedel
2009-06-02 14:36 ` [PATCH 1/4] dma-debug: add variables and checks for driver filter Joerg Roedel
2009-06-02 14:36 ` [PATCH 2/4] dma-debug: add debugfs file " Joerg Roedel
2009-06-02 14:36 ` [PATCH 3/4] dma-debug: add dma_debug_driver kernel command line Joerg Roedel
2009-06-02 14:36 ` [PATCH 4/4] dma-debug: add documentation for the driver filter Joerg Roedel
  -- strict thread matches above, loose matches on Subject: below --
2009-05-28 15:19 [PATCH 0/4] dma-debug: " Joerg Roedel
2009-05-28 15:19 ` [PATCH 1/4] dma-debug: add variables and checks for " Joerg Roedel
2009-06-01 21:55   ` Andrew Morton
2009-06-02  8:27     ` Joerg Roedel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.