$ mkdir /debugfs $ mount -t debugfs none /debugfs
static struct dentry *root_d = debugfs_create_dir("exam_debugfs", NULL); //在debugfs根目录下创建新目录exam_debugfs,然会新建目录的目录项指针 static u8 var8; debugfs_create_u8("var-u8", 0664, root_d, &var8); //在exam_debugfs中创建变量var8对应的文件,名为var-u8,权限为0664 static u32 varbool; debugfs_create_bool("var-bool", 0664, root_d, &varbool); //bool变量
char buf[] = "Hello debugfs!\n"; b.data = buf; b.size = strlen(buf) + 1; debugfs_create_blob("blob", 0644, root_d, &b); // blob is readonly, even if 0644没错,debugfs提供的debugfs_blob_wrapper结构所导出的数据块只能读取,不能修改。
u32 arr[] = {1,2,3,4,5}; debugfs_create_u32_array("array", 0664, root_d, arr, sizeof(arr)/sizeof(u32));
struct dentry* debugfs_create_file ( const char * name, umode_t mode, struct dentry * parent, void * data, // 传入的data指针会被赋值给新建文件对应inode的i_private字段 const struct file_operations * fops )下面,仿照struct debugfs_blob_wrapper的实现,实现struct my_blob_wrapper和my_blob_wrapper_ops,提供可读写的“blob”:
/** 自定义可读写blob **/ struct my_blob_wrapper{ void *data; unsigned long size; // data缓冲区长度 }; static int my_blob_wrapper_open(struct inode *inode, struct file *filp) { filp->private_data = inode->i_private; // inode->i_private被设置为debugfs_create_file传入的data参数 return 0; } static ssize_t my_blob_wrapper_read(struct file *filp, char __user *user_buf, size_t count, loff_t *ppos) { struct my_blob_wrapper *blob = filp->private_data; return simple_read_from_buffer(user_buf, count, ppos, blob->data, blob->size);//此函数有libfs提供,与下面逻辑等价 // if (*ppos >= blob->size) { // return 0; // } // if (*ppos + count > blob->size) { // count = blob->size - *ppos; // } // if (copy_to_user(user_buf, blob->data + *ppos, count) != 0) { // return -EFAULT; // } // *ppos += count; // return count; } static ssize_t my_blob_wrapper_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *ppos) { struct my_blob_wrapper *blob = filp->private_data; return simple_write_to_buffer(blob->data, blob->size, ppos, user_buf, count);//此函数由libfs提供,与下面逻辑等价 // if (*ppos >= blob->size) { // return 0; // } // if (*ppos + count > blob->size) { // count = blob->size - *ppos; // } // if (copy_from_user(blob->data + *ppos, user_buf, count) != 0) { // return -EFAULT; // } // *ppos += count; // return count; } static struct file_operations my_blob_wrapper_ops = { .owner = THIS_MODULE, .open = my_blob_wrapper_open, .read = my_blob_wrapper_read, .write = my_blob_wrapper_write, .llseek = default_llseek,//VFS提供 }; struct dentry *my_create_blob(const char *name, umode_t mode, struct dentry *parent, struct my_blob_wrapper *blob) { return debugfs_create_file(name, mode, parent, blob, &my_blob_wrapper_ops); } /* done */
#include <linux/module.h> #include <linux/debugfs.h> #include <linux/fs.h> // for libfs #include <asm-generic/uaccess.h> /** 自定义可读写blob **/ struct my_blob_wrapper{ void *data; unsigned long size; }; static int my_blob_wrapper_open(struct inode *inode, struct file *filp) { filp->private_data = inode->i_private; return 0; } static ssize_t my_blob_wrapper_read(struct file *filp, char __user *user_buf, size_t count, loff_t *ppos) { struct my_blob_wrapper *blob = filp->private_data; return simple_read_from_buffer(user_buf, count, ppos, blob->data, blob->size); // from libfs } static ssize_t my_blob_wrapper_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *ppos) { struct my_blob_wrapper *blob = filp->private_data; return simple_write_to_buffer(blob->data, blob->size, ppos, user_buf, count); } static struct file_operations my_blob_wrapper_ops = { .owner = THIS_MODULE, .open = my_blob_wrapper_open, .read = my_blob_wrapper_read, .write = my_blob_wrapper_write, .llseek = default_llseek, // from vfs }; /* 接口函数 */ struct dentry *my_create_blob(const char *name, umode_t mode, struct dentry *parent, struct my_blob_wrapper *blob) { return debugfs_create_file(name, mode, parent, blob, &my_blob_wrapper_ops); } /** my_clob implementation end **/ static struct dentry *root_d; static u8 var8; static u16 var16; static u32 var32; static u32 varbool; static char buf[] = "Hello debugfs!\n"; static struct debugfs_blob_wrapper b; static struct my_blob_wrapper b2; static u32 arr[] = {1,2,3,4,5}; int __init mod_init(void) { printk(KERN_INFO "exam_debugfs: initialing...\n"); root_d = debugfs_create_dir("exam_debugfs", NULL); if (!root_d) { printk(KERN_INFO "exam_debugfs: error create root dir\n"); return 1; } /* u{8,16,32}, bool */ debugfs_create_u8("var-u8", 0664, root_d, &var8); debugfs_create_u16("var-u16", 0664, root_d, &var16); debugfs_create_u32("var-u32", 0664, root_d, &var32); debugfs_create_bool("var-bool", 0664, root_d, &varbool); /* u32_array */ debugfs_create_u32_array("array", 0664, root_d, arr, sizeof(arr)/sizeof(u32)); /* blob_wrapper */ b.data = buf; b.size = strlen(buf) + 1; debugfs_create_blob("blob", 0644, root_d, &b); // blob is readonly, even if 0644 /* my_blob_wrapper */ b2.data = buf; b2.size = strlen(buf) + 1; my_create_blob("myblob", 0644, root_d, &b2); return 0; } void __exit mod_exit(void) { debugfs_remove_recursive(root_d); printk(KERN_INFO "exam_debugfs: exiting...\n"); } module_init(mod_init); module_exit(mod_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("a demo for debugfs"); MODULE_AUTHOR("rsljdkt");
static ssize_t read_file_bool(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { char buf[3]; u32 *val = file->private_data; if (*val) buf[0] = 'Y'; else buf[0] = 'N'; buf[1] = '\n'; buf[2] = 0x00; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); } static ssize_t write_file_bool(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { char buf[32]; size_t buf_size; bool bv; u32 *val = file->private_data; buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; if (strtobool(buf, &bv) == 0) *val = bv; return count; }
Function Documentation http://docs.huihoo.com/doxygen/linux/kernel/3.7/fs_2debugfs_2file_8c.html#ad5e6fa7f4a3de8d751a7fff4d99e59f3
Linux内核里的DebugFS http://www.cnblogs.com/wwang/archive/2011/01/17/1937609.html