debugfs is a simple memory-based filesystem, designed specifically to debug Linux kernel code, and not to be confused with the debugfs filesystem utility. Introduced by Greg Kroah-Hartman in December 2004, debugfs helps kernel developers export large amounts of debug data into user-space. This article introduces debugfs and its application programming interface, along with sample code. The intended audience are kernel and device driver developers with some knowledge of Linux kernel development. The experienced can use it to refresh their skills as well.
Greg Kroah-Hartman introduced debugfs to the Linux kernel through his post to the Linux kernel mailing list (LKML) in December 2004. debugfs helps kernel developers export large amounts of debug data into user-space. It has no rules about any information that can be put in, unlike /proc
and /sysfs
, and hence is encouraged for use in debugging. Using printk
can suffice when reading values — but it does not allow developers to change values of variables from user-space.
Prerequisites
A test system with kernel development environment requires Linux kernel source code for reference. Pretty much any distribution with a kernel version higher than 2.6.10-rc3 supports debugfs, but the newer the kernel, the more API support you get.
My setup consists of Fedora 13 (x86_64) and the latest linux-next kernel.
Setting up DebugFS
If you are using one of the latest distributions, chances are that debugfs is already set up on your machine. If you’re compiling the kernel from scratch, make sure you enable debugfs in the kernel configuration. Once you reboot to your newly compiled kernel, check if debugfs is already mounted, with the following command:
# mount | grep debugfs none on /sys/kernel/debug type debugfs (rw)
If you see output as above, you have debugfs pre-mounted. If not, you can mount it (as root) with the command shown below:
# mount -t debugfs nodev /sys/kernel/debug
If you want it to be available on every reboot, append an entry in /etc/fstab
as follows:
debugfs /sys/kernel/debug debugfs defaults 0 0
Once mounted, you can view a lot of files and directories in /sys/kernel/debug
, each belonging to one or the other subsystem.
The debugfs API
To access the API, include linux/debugfs.h
in your source file. To be able to use debugfs, we start by creating a directory within /sys/kernel/debug
, which is an ideal way to start. The rest of the files can be placed within this directory.
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
Here, is the name of the directory, and parent is the parent directory (if null, the directory is created in /sys/kernel/debug
). If debugfs is not enabled in the kernel, ENODEV
is returned.
If you need to create a single file within debugfs, you can call the following function:
struct dentry *debugfs_create_file(const char *name, mode_t mode, struct dentry *parent, void *data, struct file_operations *fops);
Here, name
is the file name to be created; mode stands for the permissions of the created file; parent
specifies the parent directory in which the file should be created (if null, it defaults to the debugfs root, /sys/kernel/debug
); data
is the type inode.i_private
and fops
is the file operations.
If you need to write to and read from a single value, you can use this to create an unsigned 8-bit value:
struct dentry *debugfs_create_u8(const char *name, mode_t mode, struct dentry *parent, u8 *value);
Here, value
is a pointer to a variable that needs to be read and written to.
A few other helper functions to create files with single integer values are:
struct dentry *debugfs_create_u16
struct dentry *debugfs_create_u32
struct dentry *debugfs_create_u64
(Refer to fs/debugfs/file.c
for more information.)
Similar functions that give hex output, are:
dentry *debugfs_create_x8(const char *name, mode_t mode, struct dentry *parent, u8 *value) dentry *debugfs_create_x16 dentry *debugfs_create_x32 ^^dentry *debugfs_create_x64
Note: debugfs_create_x64
is the most recent edition of the API; added in May 2010 by Huang Ying, this tells us that debugfs is still in active development.
Clean up!
One important thing to remember is that all the files and directories created using the above APIs are to be cleaned up by the creator, using the following code:
void debugfs_remove(struct dentry *dentry)
Here, dentry
is a pointer to the file or directory that needs to be cleaned up.
Other available DebugFS APIs are:
debugfs_create_symlink
— create symbolic link in debugfsdebugfs_remove_recursive
— recursive removal of a directory treedebugfs_rename
— rename a file or directorydebugfs_initialized
— to know whether debugfs is registereddebugfs_create_bool
— to read/write a boolean valuedebugFS_create_blob
— to read a binary large object
You can refer to code for these and other functions in fs/debugfs/{inode.c, file.c}
in the kernel directory.
On a general note, debugfs is not considered to be a stable Application Binary Interface (ABI), and hence it should only be used to collect debug information on a temporary basis. For more information in this regard, you can refer to an LWN article.
Code sample
Note: You need to be running the latest kernel to make this program work.
This sample program, my_debugfs.c
, shows a use of debugfs.
#include <linux/init.h> #include <linux/module.h> #include <linux/debugfs.h> /* this is for DebugFS libraries */ #include <linux/fs.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Surya Prabhakar <surya_prabhakar@dell.com>"); MODULE_DESCRIPTION("sample code for DebugFS functionality"); #define len 200 u64 intvalue,hexvalue; struct dentry *dirret,*fileret,*u64int,*u64hex; char ker_buf[len]; int filevalue; /* read file operation */ static ssize_t myreader(struct file *fp, char __user *user_buffer, size_t count, loff_t *position) { return simple_read_from_buffer(user_buffer, count, position, ker_buf, len); } /* write file operation */ static ssize_t mywriter(struct file *fp, const char __user *user_buffer, size_t count, loff_t *position) { if(count > len ) return -EINVAL; return simple_write_to_buffer(ker_buf, len, position, user_buffer, count); } static const struct file_operations fops_debug = { .read = myreader, .write = mywriter, }; static int __init init_debug(void) { /* create a directory by the name dell in /sys/kernel/debugfs */ dirret = debugfs_create_dir("dell", NULL); /* create a file in the above directory This requires read and write file operations */ fileret = debugfs_create_file("text", 0644, dirret, &filevalue, &fops_debug); /* create a file which takes in a int(64) value */ u64int = debugfs_create_u64("number", 0644, dirret, &intvalue); if (!u64int) { printk("error creating int file"); return (-ENODEV); } /* takes a hex decimal value */ u64hex = debugfs_create_x64("hexnum", 0644, dirret, &hexvalue ); if (!u64hex) { printk("error creating hex file"); return (-ENODEV); } return (0); } module_init(init_debug); static void __exit exit_debug(void) { /* removing the directory recursively which in turn cleans all the file */ debugfs_remove_recursive(dirret); } module_exit(exit_debug);
Building the module
Create a Makefile
like the following one, to compile and test this code:
obj-m := my_debugfs.o KDIR := /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) all: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
Further reading and references
For those who are unaware, there’s lot of information already available; LWN and the LKML mailing list are good sources of knowledge. If you want to look at the relevant kernel source code, you can visit:
You can observe the latest changes in debugfs by examining the online Git repository at kernel.org. Within the kernel source, you can refer to Documentation/filesystems/debugfs.txt
.
[…] on the machine you want to use ftrace on. If you are unaware of how to set up debugfs, do refer to my debugfs article from last month.debugfs should have been mounted on /sys/kernel/debugfs, and if tracing is enabled, you should be […]