On Thu, Jul 24, 2014 at 04:18:01PM +0100, Rob Jones wrote: > Reviewed-by: Ian Molton <ian.molton@xxxxxxxxxxxxxxx> > Suggested-by: Ben Dooks <ben.dooks@xxxxxxxxxxxxxxx> > Signed-off-by: Rob Jones <rob.jones@xxxxxxxxxxxxxxx> > --- > Documentation/driver-model/devres-debugfs.txt | 140 +++++++++ > drivers/base/Kconfig | 18 ++ > drivers/base/devres.c | 387 +++++++++++++++++++++++++ > 3 files changed, 545 insertions(+) > create mode 100644 Documentation/driver-model/devres-debugfs.txt > > diff --git a/Documentation/driver-model/devres-debugfs.txt b/Documentation/driver-model/devres-debugfs.txt > new file mode 100644 > index 0000000..7004ebd > --- /dev/null > +++ b/Documentation/driver-model/devres-debugfs.txt > @@ -0,0 +1,140 @@ > + > +Introduction > +============ > + > +This document describes a file system that can be enabled to assist > +with the debugging of devices that use managed reources > + > +Outline of Operation > +==================== > + > +Setting the flag DEVRES_DEBUGFS (depends on DEBUG_DEVRES) enables a > +debug facility for device managed resources. This takes the form of > +a directory in the debugfs file system which is a pseudo file system > +(typically mounted at /sys/kernel/debug) similar in concept to sysfs > +but with no restrictions on the format of the data read from a file. > + > +The directory (devres/) is created the first time a managed resource > +is allocated for any device. > + > +The first time a managed resource is allocated for a device, a file > +with the same name as the device is created in devres/. > + > +The file is read only and can be read by normal userspace utilities > +(such as cat). > + > +The data returned is in ASCII text format and has one header line for > +the device followed by one line per allocated resource. > + > +It is possible to seek to a given line within the file: position 0 > +(zero) goes directly to the device line, position 1 goes to the first > +resource line and so on. Attempting to seek to a line that does not > +exist returns EOF. > + > +If opened and read sequentially, a file will initially give Line 0 (see > +below) and then each subsequent read will give a Resource Line until > +EOF. Note that the data may change on the fly (see Notes below). > + > +Data Format > +=========== > + > +Device Line (Line 0) > +-------------------- > + > +dev: <address> <name> > + > +There is a single space between each field. > + > +dev: = literal text identifying this as a device line. > + > +<address> = the address in kernel memory of the device data structure. > +The layout of "struct device" can be found in include/linux/device.h. > +This value is displayed in hexadecimal format using the "%p" format > +specifier and thus will vary in length depending on the word size of > +the kernel, e.g. 8 characters for a 32 bit kernel. > + > +<name> = the name of the device. This should be the same as the file > +name, it is included to facilitate identification when multiple > +devices are being listed. The length of this field can vary. > + > +Resource Line (Line 1 et seq.) > +------------------------------ > + > +res: <address> <length> <data> <name> > + > +There is a single space between each field. > + > +res: = literal text identifying this as a resource line. > + > +<address> = the address in kernel memory of the resource data. The > +structure pointed to can vary depending on the type of resource. > +This field is encoded in hexadecimal format using the "%p" format > +specifier and thus will vary in length depending on the word size of > +the kernel, e.g. 8 characters for a 32 bit kernel. > + > +<length> = the length of the resource data. This field is encoded > +in decimal format, right justified, space filled and is always 9 > +characters long. > + > +<data> = a hexadecimal display of the first 16 (or <length> if less) > +bytes of data starting for location <address>. If <length> is less > +than 16, this field is padded with spaces on the right to the full > +32 characters. > + > +<name> = a string indentifying the resource type. This is often a > +string containing the name of the function to be used to free the > +resource. Typical examples are "devm_kzalloc_release" which identifies > +a memory resource and "devm_gpio_release" which identifies a gpio > +resource. The length of this field can vary. > + > +Notes > +===== > + > +1. Once created, a file persists until the device is removed even > + if all allocated resources are freed. This means that the existence > + of the file is confirmation that at least one resource has been > + allocated at some point, even if the device now has none allocated. > + > +2. Opening a file and holding it open will prevent the freeing up of > + of the device - the final removal is held off until the file is > + closed. Managed resources can still be freed if, say, a driver is > + removed. > + > +3. Resources can, in principle, be allocated and freed on the fly so > + it should not be assumed in general that seeking to a particular > + resource line will always return the same resource. However, that is > + a function of the device driver concerned and it may be a valid > + assumption for some drivers, e.g. one that only allocates resources > + during its .probe function. > + > +4. The device's list of resources is traversed from its base to the > + requested item each time the file is read. During this scan resources > + are spinlocked, which may have implications if resources can be > + allocated during time critical code at the same time as a read is > + taking place. > + > +5. A copy is taken of (up to) 16 bytes of resource data while the > + spinlock (see note 4, above) is still in place and so can be relied > + upon as an accurate snapshot at the time of the read but it must be > + remembered that resources may change dynamically (see note 3, above) > + so the memory may have changed subsequently. > + > +Sample Output > +============= > + > +root@arm:~# cat /sys/kernel/debug/devres/mmc0 > +dev: ed980008 mmc0 > +res: ed95a618 50 000000004884e8800001000039a695ed devm_kzalloc_release > +res: ed95cc58 4 02000000 devm_gpio_release > +res: ed95cc98 8 a2000000000098ed devm_irq_release > +root@arm:~# > + > +This shows three managed resources allocated to device "mmc0". > + > +1. A block of memory 50 bytes long (the first 16 byte are displayed). > +2. A GPIO. > +3. An IRQ. > + > +If 16 bytes of data is insufficient, you can try using other debugging > +tools to examine the data. Why did you pick 16 bytes? What can I do with that information? > diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig > index 8fa8dea..6a2f125 100644 > --- a/drivers/base/Kconfig > +++ b/drivers/base/Kconfig > @@ -177,6 +177,24 @@ config DEBUG_DEVRES > > If you are unsure about this, Say N here. > > +config DEVRES_DEBUGFS > + bool "Managed device resources debugfs file system" > + depends on DEBUG_DEVRES > + help > + This option enables a debugfs file system related to Managed > + Resources. When a device allocates a managed resource, with > + this option enabled, a read-only file with the same name as > + the device is created in the file system. Reading this file > + provides some basic debug information about the managed > + resources allocated to the device. > + > + The overhead caused by enabling this option is quite small. > + Specifically, a small memory overhead for each device and a > + small time overhead at each resource allocation and > + de-allocation. > + > + If you are unsure about this, Say N here. > + > config SYS_HYPERVISOR > bool > default n > diff --git a/drivers/base/devres.c b/drivers/base/devres.c > index 5c88a27..41b6465 100644 > --- a/drivers/base/devres.c > +++ b/drivers/base/devres.c > @@ -7,9 +7,13 @@ > * This file is released under the GPLv2. > */ > > +#include <linux/debugfs.h> > #include <linux/device.h> > #include <linux/module.h> > +#include <linux/seq_file.h> > #include <linux/slab.h> > +#include <linux/spinlock.h> > +#include <linux/uaccess.h> why not just make this a separate file, that would remove the #ifdef from this file, right? > +/** > + * devres_dbgfs_seq_show - seq file output routine for a devres debugfs file > + * @s: pointer to seq file structure > + * @v: pointer to private data set up by devres_dbgfs_seq_next(). > + * > + * Static debug function called when the user reads from a device managed > + * resources debugfs file. It outputs to the user buffer using seq_file > + * function seq_printf(); > + * > + * This function locks devres_lock in the device structure. > + */ > +static int devres_dbgfs_seq_show(struct seq_file *s, void *v) > +{ > + struct devres_dbgfs_private *priv = v; > + struct device *dev = priv->dev; > + int size, i, pos = priv->pos; > + struct devres *dr; > + struct list_head *head; > + struct list_head *item; > + unsigned long flags; > + char data[16]; > + char *dataptr; > + > + if (pos == 0) { > + seq_printf(s, "dev: %p %s\n", dev, dev_name(dev)); %pK please for all kernel pointers. > +/** > + * devres_dbgfs_create_file - create debugfs file for a device > + * @dev: device > + * > + * Static debug function that will automatically create a debugfs file > + * with the same name as the supplied device IFF the said file has not > + * already been created. > + * > + * This function locks devres_dbgfs_lock. > + */ > +static void devres_dbgfs_create_file(struct device *dev) > +{ > + struct dentry *debugfsfile = NULL; > + struct devres_dbgfs_link *link; > + struct dentry *debugfsdir; > + unsigned long flags; > + > + spin_lock_irqsave(&devres_dbgfs_lock, flags); > + > + link = devres_dbgfs_find_filelink(dev); > + if (link) > + goto out_unlock; > + > + debugfsdir = devres_dbgfs_get_dir(); > + if (debugfsdir) > + /* Create file, n.b. dev goes into inode->i_private */ > + debugfsfile = debugfs_create_file(dev_name(dev), 0444, > + debugfsdir, dev, > + &devres_dbgfs_seq_fops); I worry about this, as there is no reason that devices have to have "unique" names in the system. Odds are, there's lots of conflicts, which is why sysfs is a tree, not a flat heirachy. > + if (!debugfsfile) > + goto out_unlock; If debugfs is not enabled, this will not trigger, are you sure you want that? > + > + /* Success: now create filelink entry in linked list */ > + link = kmalloc(sizeof(*link), GFP_KERNEL); > + if (!link) { > + debugfs_remove(debugfsfile); > + goto out_unlock; > + } > + > + INIT_LIST_HEAD(&link->list); > + link->dev = dev; > + link->dp = debugfsfile; > + if (devres_dbgfs_lastused) > + list_add(&link->list, &devres_dbgfs_lastused->list); > + devres_dbgfs_lastused = link; > + > +out_unlock: > + spin_unlock_irqrestore(&devres_dbgfs_lock, flags); > +} > +#endif /* CONFIG_DEVRES_DEBUGFS */ > + > /* > * Release functions for devres group. These callbacks are used only > * for identification. > @@ -220,6 +601,9 @@ void devres_add(struct device *dev, void *res) > spin_lock_irqsave(&dev->devres_lock, flags); > add_dr(dev, &dr->node); > spin_unlock_irqrestore(&dev->devres_lock, flags); > +#ifdef CONFIG_DEVRES_DEBUGFS > + devres_dbgfs_create_file(dev); > +#endif /* CONFIG_DEVRES_DEBUGFS */ ifdefs like this are strongly discouraged. Overall, I'm curious as to what this code is good for? What use cases will benifit for seeing all of this information? Why would a developer ever care about all of the resources that a specific device has created, what could I do with that information? It seems "neat", but not something I would ever actually care about, as there's nothing to do with that info. A device will never allocate something it doesn't actually need, right? thanks, greg k-h -- To unsubscribe from this list: send the line "unsubscribe linux-doc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html