定位的一个yaffs2文件系统的bug
2016-02-29 21:53
507 查看
定位了一个yaffs文件系统的bug,分享出来,如果有遇到相同的问题,少走弯路。
linux内核版本为2.6.32,yaffs版本为最新版本。
问题现象:
yaffs代码在yaffs_flus_inodes函数中出现死循环:
首先这个函数是在sync操作时调用的。
调用栈为:sys_sync-->sync_filesystems-->yaffs_sync_fs->yaffs_do_sync_fs-->yaffs_flush_super-->yaffs_flush_inodes
static void yaffs_flush_inodes(struct super_block *sb)
{
struct inode *iptr;
struct yaffs_obj *obj;
list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) { --------这里要遍历yaffs分区超级块的所有inodes,这里出现了死循环。
obj = yaffs_inode_to_obj(iptr);
if (obj) {
yaffs_trace(YAFFS_TRACE_OS,
"flushing obj %d", obj->obj_id);
yaffs_flush_file(obj, 1, 0, 0);
}
}
}
原因分析:
通过kdb查看寄存器分析反汇编代码,发现当前正在使用的inode的i_sb_list链表指向了自己,很明显是已经释放掉了。由于链表节点指向自己,因此造成死循环。
进一步分析linux代码,发现这个结构释放会在iput_final里进行,能走到iput_final这里,说明VFS层认为当前inode已经没有使用了。
常见的流程是进行unlink操作删除文件。
调用栈如下:
sys_unlink-->do_unlinkat-->iput-->iput_final-->generic_drop_inode-->list_del_init(&inode->i_sb_list);
初步分析是2个流程锁保护不到位,造成并发条件下出现了问题。
再查看vfs代码,将inode摘链的操作都会加inode_lock这把锁,由于这把锁的影响较大,所有涉及inode操作都可能使用这把锁,因此这把锁要尽快释放。
所以从VFS走到具体的文件系统函数之前都会释放这把锁,而YAFFS这个文件系统的本身函数,只会使用YAFFS文件系统自己的锁(yaffs_gross_lock(dev)),所以2个流程缺乏保护,造成问题。
进一步思考:
具体文件系统和VFS层应该减少联系,尤其是应该尽量避免直接操作VFS层的数据结构(如问题中的inode链表).
出问题的代码遍历链表是需要将inode转换为yaffs自己的yaffs_object.yaffs完全可以自己实现一个链表,将所有脏的yaffs_objects记录,从而与VFS层解耦。
linux内核版本为2.6.32,yaffs版本为最新版本。
问题现象:
yaffs代码在yaffs_flus_inodes函数中出现死循环:
首先这个函数是在sync操作时调用的。
调用栈为:sys_sync-->sync_filesystems-->yaffs_sync_fs->yaffs_do_sync_fs-->yaffs_flush_super-->yaffs_flush_inodes
static void yaffs_flush_inodes(struct super_block *sb)
{
struct inode *iptr;
struct yaffs_obj *obj;
list_for_each_entry(iptr, &sb->s_inodes, i_sb_list) { --------这里要遍历yaffs分区超级块的所有inodes,这里出现了死循环。
obj = yaffs_inode_to_obj(iptr);
if (obj) {
yaffs_trace(YAFFS_TRACE_OS,
"flushing obj %d", obj->obj_id);
yaffs_flush_file(obj, 1, 0, 0);
}
}
}
原因分析:
通过kdb查看寄存器分析反汇编代码,发现当前正在使用的inode的i_sb_list链表指向了自己,很明显是已经释放掉了。由于链表节点指向自己,因此造成死循环。
进一步分析linux代码,发现这个结构释放会在iput_final里进行,能走到iput_final这里,说明VFS层认为当前inode已经没有使用了。
常见的流程是进行unlink操作删除文件。
调用栈如下:
sys_unlink-->do_unlinkat-->iput-->iput_final-->generic_drop_inode-->list_del_init(&inode->i_sb_list);
初步分析是2个流程锁保护不到位,造成并发条件下出现了问题。
再查看vfs代码,将inode摘链的操作都会加inode_lock这把锁,由于这把锁的影响较大,所有涉及inode操作都可能使用这把锁,因此这把锁要尽快释放。
所以从VFS走到具体的文件系统函数之前都会释放这把锁,而YAFFS这个文件系统的本身函数,只会使用YAFFS文件系统自己的锁(yaffs_gross_lock(dev)),所以2个流程缺乏保护,造成问题。
进一步思考:
具体文件系统和VFS层应该减少联系,尤其是应该尽量避免直接操作VFS层的数据结构(如问题中的inode链表).
出问题的代码遍历链表是需要将inode转换为yaffs自己的yaffs_object.yaffs完全可以自己实现一个链表,将所有脏的yaffs_objects记录,从而与VFS层解耦。
相关文章推荐
- 免费帮助台软件、客户服务管理(CSM)和支持门票应用程序(PHP版本)
- 免费PHP基于Web的文件管理器
- yii2的表单验证与数据库操作
- ThinkPHP框架配置
- php防止sql注入
- ThinkPHP去除url中的index.php以及绑定模块
- yii2表单学习
- PHP之有关类和对象的系统函数与运算符
- Laravel 5.1 学习 之 授权
- yii2一些入门知识
- YII框架的安装出现的两个小问题
- 为什么会有OutputStreamWriter和InputStreamReader两个转换类的出现以及它们的作用
- thinkphp3.2架构及源码理解
- PHP获得数组的交集与差集
- php用explode,可以提供多个字符作为分割符来进行分割数组吗?
- 构建自己的PHP框架--实现Model类(2)
- PHP连接MySQL数据库过程
- 【PHP项目部署二】Mysql环境配置
- PHP预定义接口之 ArrayAccess
- 【PHP项目部署一】PHP环境配置