转自:http://blog.chinaunix.net/space.php?uid=20564848&do=blog&id=73448
=========================================================================================
我们对debugfs文件系统的应用之1是:drivers/gpio/gpiolib.c它创建了一个名为"gpio"的文件,然后我们可以使用
'-'表示output
'+'表示input
echo -170=0>/d/gpio
echo -96 =0>/d/gpio //必须让'='索引为4,所以需要补齐,这是驱动的一个bug
以上2个操作是将cpu的170脚和96脚置低,对于调试很方便,当然debugfs要想使用必须在make menuconfig时打开
Kernel hacking=> -*- Debug Filesystem保存之后,在
vim .config可以看到CONFIG_DEBUG_FS=y
static int __init gpiolib_debugfs_init(void)
{
/* /sys/kernel/debug/gpio */
(void) debugfs_create_file("gpio", S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP,
NULL, NULL, &gpiolib_operations);
return 0;
}
subsys_initcall(gpiolib_debugfs_init);
=========================================================================================
在我们的系统system/rootdir/init.rc启动脚本中存在如下2行,进而将debugfs文件系统挂载到/d目录下[luther.gliethttp],
...
mkdir /d
...
mount debugfs debugfs /d
这和在init进程中,通过语句mount sys,pts和dev效果一样.
mkdir("/dev", 0755);
mkdir("/dev/pts", 0755);
mkdir("/sys", 0755);
mount("tmpfs", "/dev", "tmpfs", 0, NULL);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
=========================================================================================
=>debugfs_create_file
=>simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count);
static struct vfsmount *debugfs_mount;
static int debugfs_mount_count;
static struct file_system_type debug_fs_type = {
.owner = THIS_MODULE,
.name = "debugfs",
.get_sb = debug_get_sb,
.kill_sb = kill_litter_super,
};
=========================================================================================
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;
pr_debug("debugfs: creating file '%s'\n",name);
error = simple_pin_fs(&debug_fs_type, &debugfs_mount,
&debugfs_mount_count);
if (error)
goto exit;
error = debugfs_create_by_name(name, mode, parent, &dentry);//创建名字为name的文件[目录,设备节点或者目录,符号链接等]
if (error) {
dentry = NULL;
simple_release_fs(&debugfs_mount, &debugfs_mount_count);
goto exit;
}
if (dentry->d_inode) {
if (data)
dentry->d_inode->i_private = data;//传递的open之后file结构题的private参数
if (fops)
dentry->d_inode->i_fop = fops;//如果用户定义了对新创建的inode文件的函数操作集,那么将自定义函数集作为用户程序操作该文件时,open,read,write等操作函数集,这是debugfs文件系统提供的最有用接口,让我们完全控制inode文件的操作函数集[luther.gliethttp].
}
exit:
return dentry;
}
//文件系统安装和引用计数操作
//如果debugfs文件系统超级块没有创建,那么创建之
=>
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)) { //*mount指向的存储指针的内存为0,第一次运行会执行,此时debugfs_mount存储单元中数据为0,没有指向任何数据
spin_unlock(&pin_fs_lock);
mnt = vfs_kern_mount(type, 0, type->name, NULL);
if (IS_ERR(mnt))
return PTR_ERR(mnt);
spin_lock(&pin_fs_lock);
if (!*mount)
*mount = mnt;//将mnt数据指针存储到*mount指向的指针存储空间&debugfs_mount中[luther.gliethttp].
}
mntget(*mount);
++*count;
spin_unlock(&pin_fs_lock);
mntput(mnt);
return 0;
}
=>simple_pin_fs
=>vfs_kern_mount
struct vfsmount *
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
{
struct vfsmount *mnt;
char *secdata = NULL;
int error;
if (!type)
return ERR_PTR(-ENODEV);
error = -ENOMEM;
mnt = alloc_vfsmnt(name); //从slab上摘下一个空内存对象
if (!mnt)
goto out;
if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
secdata = alloc_secdata();
if (!secdata)
goto out_mnt;
error = security_sb_copy_data(data, secdata);
if (error)
goto out_free_secdata;
}
error = type->get_sb(type, flags, name, data, mnt);//调用debug_fs_type获取超级块sb的方法
if (error < 0)
goto out_free_secdata;
BUG_ON(!mnt->mnt_sb);
error = security_sb_kern_mount(mnt->mnt_sb, secdata);
if (error)
goto out_sb;
mnt->mnt_mountpoint = mnt->mnt_root;//mount的目录项
mnt->mnt_parent = mnt;//因为是root根,所以parent为自己
up_write(&mnt->mnt_sb->s_umount);
free_secdata(secdata);
return mnt;//ok,mount结构体成功创建
out_sb:
dput(mnt->mnt_root);
up_write(&mnt->mnt_sb->s_umount);
deactivate_super(mnt->mnt_sb);
out_free_secdata:
free_secdata(secdata);
out_mnt:
free_vfsmnt(mnt);
out:
return ERR_PTR(error);
}
static int debug_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data, struct vfsmount *mnt)
{
return get_sb_single(fs_type, flags, data, debug_fill_super, mnt);//填充超级块sb的方法debug_fill_super
}
int get_sb_single(struct file_system_type *fs_type,
int flags, void *data,
int (*fill_super)(struct super_block *, void *, int),
struct vfsmount *mnt)
{
struct super_block *s;
int error;
s = sget(fs_type, compare_single, set_anon_super, NULL);
//sget=>alloc_super=>kzalloc(sizeof(struct super_block),GFP_USER);从malloc_sizes[]数组中申请一个大小适合的slab空闲对象空间
if (IS_ERR(s))
return PTR_ERR(s);
if (!s->s_root) {//ok,当前该超级块sb还没有root根目录结构体
s->s_flags = flags;
error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);//填充超级块sb的root根目录结构体
if (error) {
up_write(&s->s_umount);
deactivate_super(s);
return error;
}
s->s_flags |= MS_ACTIVE;
}
do_remount_sb(s, flags, data, 0);//执行sb->s_op->remount_fs,这里没有定义该方法
return simple_set_mnt(mnt, s);//该mount结构体管理s超级块,mnt->mnt_root = dget(sb->s_root);
}
static int debug_fill_super(struct super_block *sb, void *data, int silent)
{
static struct tree_descr debug_files[] = {{""}};
return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files);//填充超级块sb的root根目录结构体信息
//simple_fill_super
//=>inode = new_inode(s);申请节点
//=>root = d_alloc_root(inode);申请目录项dentry
//s->s_root = root;将root赋值给超级块sb,作为超级块的目录项,然后函数return 0;
}
int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
{
mnt->mnt_sb = sb;//超级块
mnt->mnt_root = dget(sb->s_root);//该超级块对应的节点目录项,
//[注意:一个文件预想在系统中存在那么必须具备1.inode节点;2.denty目录项,对于二者的关系,可以参照以前的文章[luther.gliethttp]]
return 0;
}
=========================================================================================