debugfs的精妙接口

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);
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值