debugfs_create_u32
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/uaccess.h>
static u32 tmp = 5;
static int __init my_demo_init(void)
{
pr_info("%s, ===>\n", __func__);
pr_info("%s, before debugfs create file\n", __func__);
debugfs_create_u32("u32_demo", S_IRUGO | S_IWUSR, NULL, &tmp);
pr_info("%s, <===\n", __func__);
return 0;
}
static void my_demo_exit(void)
{
pr_info("%s, ===>\n", __func__);
pr_info("%s, <===\n", __func__);
}
module_init(my_demo_init);
module_exit(my_demo_exit);
MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("kiss1994");
MODULE_DESCRIPTION ("debugfs");
root@ubuntu:/sys/kernel/debug# dmesg | grep -iE "demo"
[10279.085221] my_demo_init, ===>
[10279.085227] my_demo_init, before debugfs create file
[10279.090143] my_demo_init, <===
root@ubuntu:/sys/kernel/debug# cat u32_demo
5
root@ubuntu:/sys/kernel/debug# echo 6 > u32_demo
root@ubuntu:/sys/kernel/debug# cat u32_demo
6
//=======================================================
对应源码
static int debugfs_u32_set(void *data, u64 val)
{
*(u32 *)data = val;
return 0;
}
static int debugfs_u32_get(void *data, u64 *val)
{
*val = *(u32 *)data;
return 0;
}
// DEFINE_DEBUGFS_ATTRIBUTE 宏,用于创建一个fpos,并设置open操作
DEFINE_DEBUGFS_ATTRIBUTE(fops_u32, debugfs_u32_get, debugfs_u32_set, "%llu\n");
DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_ro, debugfs_u32_get, NULL, "%llu\n");
DEFINE_DEBUGFS_ATTRIBUTE(fops_u32_wo, NULL, debugfs_u32_set, "%llu\n");
/**
* debugfs_create_u32 - create a debugfs file that is used to read and write an unsigned 32-bit value
* @name: a pointer to a string containing the name of the file to create.
* @mode: the permission that the file should have
* @parent: a pointer to the parent dentry for this file. This should be a
* directory dentry if set. If this parameter is %NULL, then the
* file will be created in the root of the debugfs filesystem.
* @value: a pointer to the variable that the file should read to and write
* from.
*
* This function creates a file in debugfs with the given name that
* contains the value of the variable @value. If the @mode variable is so
* set, it can be read from, and written to.
*/
void debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent,
u32 *value)
{
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_u32,
&fops_u32_ro, &fops_u32_wo);
}
EXPORT_SYMBOL_GPL(debugfs_create_u32);
//这里怎么把 返回值 给阉割了?
//如果被阉割的话,就没法直接release了,见上文示例
static struct dentry *debugfs_create_mode_unsafe(const char *name, umode_t mode,
struct dentry *parent, void *value,
const struct file_operations *fops,
const struct file_operations *fops_ro,
const struct file_operations *fops_wo)
{
/* if there are no write bits set, make read only */
if (!(mode & S_IWUGO))
return debugfs_create_file_unsafe(name, mode, parent, value,
fops_ro);
/* if there are no read bits set, make write only */
if (!(mode & S_IRUGO))
return debugfs_create_file_unsafe(name, mode, parent, value,
fops_wo);
return debugfs_create_file_unsafe(name, mode, parent, value, fops);
}
//创建一个fpos,并设置open操作
#define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \
static int __fops ## _open(struct inode *inode, struct file *file) \
{ \
__simple_attr_check_format(__fmt, 0ull); \
return simple_attr_open(inode, file, __get, __set, __fmt); \
} \
static const struct file_operations __fops = { \
.owner = THIS_MODULE, \
.open = __fops ## _open, \
.release = simple_attr_release, \
.read = debugfs_attr_read, \
.write = debugfs_attr_write, \
.llseek = no_llseek, \
}
//=======================================================
正确的使用方式
【insmod和rmmod时能正确创建和删除】
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/uaccess.h>
static u32 tmp = 5;
static struct dentry *demo_dir;
static int __init my_demo_init(void)
{
pr_info("%s, ===>\n", __func__);
pr_info("%s, before debugfs create dir and file\n", __func__);
demo_dir = debugfs_create_dir("demo", NULL);// 创建目录,它的父目录是sys/kernel/debug
if (!demo_dir) {
pr_err("%s, debugfs create dir failed\n", __func__);
return -EIO;
}
debugfs_create_u32("u32_demo1", 0664, demo_dir, &tmp);
pr_info("%s, <===\n", __func__);
return 0;
}
static void my_demo_exit(void)
{
pr_info("%s, ===>\n", __func__);
debugfs_remove_recursive(demo_dir); // 里面有自动判断是否为NULL的code
pr_info("%s, <===\n", __func__);
}
module_init(my_demo_init);
module_exit(my_demo_exit);
MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("kiss1994");
MODULE_DESCRIPTION ("debugfs");
[12134.488268] my_demo_init, ===>
[12134.488279] my_demo_init, before debugfs create dir and file
[12134.488303] my_demo_init, <===
[12172.390995] my_demo_exit, ===>
[12172.391288] my_demo_exit, <===
//=======================================================
对应源码
/**
* debugfs_create_dir - create a directory in the debugfs filesystem
* @name: a pointer to a string containing the name of the directory to
* create.
* @parent: a pointer to the parent dentry for this file. This should be a
* directory dentry if set. If this parameter is NULL, then the
* directory will be created in the root of the debugfs filesystem.
*
* This function creates a directory in debugfs with the given name.
*
* This function will return a pointer to a dentry if it succeeds. This
* pointer must be passed to the debugfs_remove() function when the file is
* to be removed (no automatic cleanup happens if your module is unloaded,
* you are responsible here.) If an error occurs, ERR_PTR(-ERROR) will be
* returned.
*
* If debugfs is not enabled in the kernel, the value -%ENODEV will be
* returned.
*/
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
{
struct dentry *dentry = start_creating(name, parent);
struct inode *inode;
if (IS_ERR(dentry))
return dentry;
if (!(debugfs_allow & DEBUGFS_ALLOW_API)) {
failed_creating(dentry);
return ERR_PTR(-EPERM);
}
inode = debugfs_get_inode(dentry->d_sb);
if (unlikely(!inode)) {
pr_err("out of free dentries, can not create directory '%s'\n",
name);
return failed_creating(dentry);
}
inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
inode->i_op = &debugfs_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
inc_nlink(inode);
d_instantiate(dentry, inode);
inc_nlink(d_inode(dentry->d_parent));
fsnotify_mkdir(d_inode(dentry->d_parent), dentry);
return end_creating(dentry);
}
EXPORT_SYMBOL_GPL(debugfs_create_dir);
#define debugfs_remove_recursive debugfs_remove
/**
* debugfs_remove - recursively removes a directory
* @dentry: a pointer to a the dentry of the directory to be removed. If this
* parameter is NULL or an error value, nothing will be done.
*
* This function recursively removes a directory tree in debugfs that
* was previously created with a call to another debugfs function
* (like debugfs_create_file() or variants thereof.)
*
* This function is required to be called in order for the file to be
* removed, no automatic cleanup of files will happen when a module is
* removed, you are responsible here.
*/
void debugfs_remove(struct dentry *dentry)
{
if (IS_ERR_OR_NULL(dentry))
return;
simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count);
simple_recursive_removal(dentry, remove_one);
simple_release_fs(&debugfs_mount, &debugfs_mount_count);
}
EXPORT_SYMBOL_GPL(debugfs_remove);
//=======================================================
其他精妙接口
/*
* debugfs_create_x{8,16,32,64} - create a debugfs file that is used to read and write an unsigned {8,16,32,64}-bit value
*
* These functions are exactly the same as the above functions (but use a hex
* output for the decimal challenged). For details look at the above unsigned
* decimal functions.
*/
/**
* debugfs_create_x8 - create a debugfs file that is used to read and write an unsigned 8-bit value
* @name: a pointer to a string containing the name of the file to create.
* @mode: the permission that the file should have
* @parent: a pointer to the parent dentry for this file. This should be a
* directory dentry if set. If this parameter is %NULL, then the
* file will be created in the root of the debugfs filesystem.
* @value: a pointer to the variable that the file should read to and write
* from.
*/
void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent,
u8 *value)
{
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_x8,
&fops_x8_ro, &fops_x8_wo);
}
EXPORT_SYMBOL_GPL(debugfs_create_x8);
//=======================================================
/**
* debugfs_create_bool - create a debugfs file that is used to read and write a boolean value
* @name: a pointer to a string containing the name of the file to create.
* @mode: the permission that the file should have
* @parent: a pointer to the parent dentry for this file. This should be a
* directory dentry if set. If this parameter is %NULL, then the
* file will be created in the root of the debugfs filesystem.
* @value: a pointer to the variable that the file should read to and write
* from.
*
* This function creates a file in debugfs with the given name that
* contains the value of the variable @value. If the @mode variable is so
* set, it can be read from, and written to.
*/
void debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent,
bool *value)
{
debugfs_create_mode_unsafe(name, mode, parent, value, &fops_bool,
&fops_bool_ro, &fops_bool_wo);
}
EXPORT_SYMBOL_GPL(debugfs_create_bool);
//=======================================================
void debugfs_create_u8(const char *name, umode_t mode, struct dentry *parent, u8 *value);
void debugfs_create_u16(const char *name, umode_t mode, struct dentry *parent, u16 *value);
void debugfs_create_u32(const char *name, umode_t mode, struct dentry *parent, u32 *value);
void debugfs_create_u64(const char *name, umode_t mode, struct dentry *parent, u64 *value);
void debugfs_create_ulong(const char *name, umode_t mode, struct dentry *parent, unsigned long *value);
void debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, u8 *value);
void debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, u16 *value);
void debugfs_create_x32(const char *name, umode_t mode, struct dentry *parent, u32 *value);
void debugfs_create_x64(const char *name, umode_t mode, struct dentry *parent, u64 *value);
void debugfs_create_size_t(const char *name, umode_t mode, struct dentry *parent, size_t *value);
void debugfs_create_atomic_t(const char *name, umode_t mode, struct dentry *parent, atomic_t *value);
void debugfs_create_bool(const char *name, umode_t mode, struct dentry *parent, bool *value);
void debugfs_create_str(const char *name, umode_t mode, struct dentry *parent, char **value);
void debugfs_create_regset32(const char *name, umode_t mode, struct dentry *parent, struct debugfs_regset32 *regset);
void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, int nregs, void __iomem *base, char *prefix);
void debugfs_create_u32_array(const char *name, umode_t mode, struct dentry *parent, struct debugfs_u32_array *array);