Chinaunix首页 | 论坛 | 博客
  • 博客访问: 56637
  • 博文数量: 22
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 60
  • 用 户 组: 普通用户
  • 注册时间: 2014-02-19 13:46
文章分类
文章存档

2015年(8)

2014年(14)

我的朋友

分类: LINUX

2014-12-28 15:48:06

linux内核和用户通信方法中有一个叫做debugfs,它的作用类似于sysctl,但是是通过文件系统实现的,本文不准备再详细的说debugfs的实现,像前面seqfile那么详细的说,而是简单列出需要的代码做个纪念,证明今天(2009/2/19)我详细的读过了linux内核的debugfs。
#define DEFINE_SIMPLE_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 struct file_operations __fops = {                                /
         .owner   = THIS_MODULE,                                        /
         .open    = __fops ## _open,                                    /
         .release = simple_attr_close,                                  /
         .read    = simple_attr_read,                                   /
         .write   = simple_attr_write,                                  /
};
以上这个宏简直太帅了,它其实定义了debugfs的file_operations,因为debugfs不是通过一个file_operations来实现的,而是每一个数据类型一个,因此用到了上面的宏来为如此繁多的file_operations服务。
int simple_attr_open(struct inode *inode, struct file *file, u64 (*get)(void *), void (*set)(void *, u64), const char *fmt)
{
         struct simple_attr *attr;   //重要结构
         attr = kmalloc(sizeof(*attr), GFP_KERNEL);
         if (!attr)
                 return -ENOMEM;
         attr->get = get;
         attr->set = set;
         attr->data = inode->u.generic_ip;
         attr->fmt = fmt;
         mutex_init(&attr->mutex);
         file->private_data = attr;
         return nonseekable_open(inode, file);
}
这个debugfs_create_XX就是定义一个特定数据类型的变量,内核和用户通过该变量进行通信,每一个变量在用户空间挂载的debugfs挂载点路径下都会有一个文件,对该文件的操作就触发了用上面宏定义的file_operations的回调函数调用事件。
struct dentry *debugfs_create_u8(const char *name, mode_t mode, struct dentry *parent, u8 *value)
{
         return debugfs_create_file(name, mode, parent, value, &fops_u8);
}
struct dentry *debugfs_create_file(const char *name, mode_t mode, struct dentry *parent, void *data, const struct file_operations *fops)
{
         struct dentry *dentry = NULL;
         int error;
         error = simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count);
...
         error = debugfs_create_by_name(name, mode, parent, &dentry);
...
         if (dentry->d_inode) {
                 if (data)
                         dentry->d_inode->u.generic_ip = data;
                 if (fops)
                         dentry->d_inode->i_fop = fops;
         }
...
}
int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *count)
{
         struct vfsmount *mnt = NULL;
         spin_lock(&pin_fs_lock);
         if (unlikely(!*mount)) {
                 spin_unlock(&pin_fs_lock);
                 mnt = vfs_kern_mount(type, 0, type->name, NULL);
...
                 spin_lock(&pin_fs_lock);
                 if (!*mount)
                         *mount = mnt;
         }
...
         return 0;
}
下面的这个read函数就是那个宏定义的file_operations中的read,真正实现在attr中的get例程
ssize_t simple_attr_read(struct file *file, char __user *buf, size_t len, loff_t *ppos)
{
         struct simple_attr *attr;
         size_t size;
         ssize_t ret;
         attr = file->private_data;
         if (!attr->get)
                 return -EACCES;
         mutex_lock(&attr->mutex);
         if (*ppos)
                 size = strlen(attr->get_buf);
         else      
                 size = scnprintf(attr->get_buf, sizeof(attr->get_buf), attr->fmt,(unsigned long long)attr->get(attr->data));
         ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size);
         mutex_unlock(&attr->mutex);
         return ret;
}
最后来看看对于u8的file_operations是怎么实现的:
DEFINE_SIMPLE_ATTRIBUTE(fops_u8, debugfs_u8_get, debugfs_u8_set, "%llu/n");
static void debugfs_u8_set(void *data, u64 val)
{
         *(u8 *)data = val;
}
static u64 debugfs_u8_get(void *data)
{
         return *(u8 *)data;
}
看完了这一切后,我不禁感叹,linux中如此简单就可以实现一个机制,太妙了。前面的seqfile是自成体系的一套机制,它强调一种抽象的思想,而这个debugfs是用文件系统实现的,linux的vfs简直太强大了,这都要归功于file_operations结构体,它就是一个适配器,适配了上面统一的调用层和下面不同的文件系统,file_operations是机制,它的实现是策略,既然是策略,那它就可以随意实现了,于是你想实现一个内核机制的时候,文件系统总会帮你,也正是因为如此,一般的内核新机制都是在文件系统上实现的。

阅读(1204) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~