浅析debugfs文件系统调试阶段gpio使用范例

浅析debugfs文件系统调试阶段gpio使用范例

=========================================================================================
我们对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;
}
=========================================================================================

你可能感兴趣的:(文件系统,浅析,范例,GPIO,debugfs)