浅析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; } =========================================================================================
|