分类: LINUX
2013-01-07 00:43:46
struct inode 里面有 15 个成员最为重要, 分成4类:
1. 链表类,
i_hash 将 inode 链接入 inode hashtable, 外部可以通过 super_block 指针与 ino 来找到这个 inode
i_dentry 为 inode 的 dentry 链表表头, 从而一个 inode 可以在文件树中有多个硬链接
i_list 将 inode 链接入 inode_used 链表
2. 属性类
i_ino, inode number
i_mode, 文件 RWX 属性及文件类型, 比如是否是文件夹, 普通文件, 或者设备文件等
i_dev, inode 所在设备的设备号, 从 super_block->s_dev 中来;而 super_block->s_dev 一般从 bdev->bd_dev 而来, 而 bdev 是该设备文件在 devfs 中的 inode 初始化时创建的, bdev->bd_dev 一般来自该设备文件的 inode->rdev, 而 redev 其实就是在devfs 中mknod 时的主设备/从设备号而来; 转了一大圈, 最终效果是 mknod 指定的设备号被赋予该设备 super block 及 inode 中的 dev 信息。
i_rdev, 这个和上面的其实是相关的, devfs 中的设备文件在内存中创建 inode 结构时, 会最终将该设备的设备号经过二进制逻辑操作而生成 i_rdev 记录在 devfs 中的 inode 的 i_rdev 里面, 以后, 如果mount 这个设备, 这个 rdev 又会记录在被 mount 进的设备的 super block及 inode 中
i_nlink, 硬链接数
i_count, inode 引用计数
3. 指针类
i_op, inode_operations 结构指针, read_inode 时根据 inode 类型(保存在 i_mode中) 进行指定
i_fop, file_operaitons 结构指针, read_inode 时根据 inode 类型(保存在 i_mode中) 进行指定
i_sb, super_block 指针
i_mapping, address_space 结构指针, 和页面交换相关
4. 特殊类
比如 i_pipe, 应该只有 inode 为管道时才有意义
i_bdev, 也只有 inode 为块设备文件时才会有意义。
其余还有些成员, 比如 gid, uid 之类, 从文件系统自身实现及与其他子系统联系看, 没什么太重要的, 重要的应该是上面这些。
文件系统几个函数跳转表总结一下:
super block operations 在 read_super 时赋给 super_block->s_op 指针
file_operations, inode_operations 都是在 read_inode时根据 inode 的不同类型赋得值, 保存在 inode->i_op, inode->i_fop 中
dentry_operations 是在 inode->i_op->lookup 时赋值给被 lookup 的 dentry 的 f_op 成员的
而 read_super 是文件系统数据结构的成员, 典型 mount 命令如:
mount -t ext2 /dev/hdxxx /mnt/tmp 命令行包含了几个信息:
1. 文件系统类型, 这里是 ext2, 从这里就能得到 read_super 函数指针
2. 设备文件, 这里是 /dev/hdxxx. 从这里得到路径名, 从而可以通过 path_walk 获得该设备文件的 dentry, 及 inode, 并在初始化 inode 的时候获得其 rdev 并创建 bdev, inode 保持其一个引用, 至于 bdev 的 block_device_operations 指针则要么通过 rdev 号为下标从内核全局数组 blddevs 获得, 或者靠其 inode为下标 从另一个全局数组中获得
3. 挂载点, 这里是 /mnt/tmp, 同样可以通过 path_walk 获得其 dentry;
通过这些信息, bdev 执行 bdev->bd_op->open 操作, 如果成功, 则执行 fs->read_super 操作, 如果也成功, 则被打开的 bdev 会有一个引用保存在 super block 中, 由于此, 在mount结束阶段, 释放 /dev/hdxxx 对应的dentry 时, 同时也会因为有 inode 的释放进一步导致 bdev的释放(inode 保持其一个引用), 如果没有 super block 这个引用, bdev 就真的释放了。
再得到super_block 之后, mount 过程继续, 会调用 add_vfsmount, 在这个函数里, 会创建一个 vfsmount结构, vfsmount 结构有如下重要成员:
1. 指针类
mnt_parent, 指向上一级 vfsmount 结构, 也就是这里的 /mnt/tmp 所在的设备的挂在点的 vfsmount 结构
mnt_mountpoint, 指向 /mnt/tmp 的 dentry 结构
mnt_root, 指向新创建的 superblock 的 s_root dentry 结构, 这个结构是 read_super 时创建的该设备的根目录
mnt_sb, 指向新创建的 super_block
2. 链表类
mnt_child, 将这个 vfsmount结构链接入上一级 vfsmount 的 mnt_mounts 链表
mnt_clash, 将这个 vfsmount 结构链接入 mnt_mountpoint 的 d_vfsmnt 链表
mnt_mounts, 自己的子 vfsmount 链表表头, 用来链将来的下一级vfsmount 的
mnt_instance, 将这个 vfsmount 结构链接入 super_block 的 s_mounts 链表, 因为一个设备可以被同时挂载到不同的路径上, 因此, vfsmount 与 super block 也是 多 对 1 的关系
mnt_list 将这个 vfsnount 结构链接入一个链接所有的 vfsmount 的链表
将这些指针与链接操作完毕后, mount 也就完成了, 从文件树向下, 如果发现一个 dentry->d_vfsmnt 链表非空, 就可知为一个挂载点, 根据 vfsmnt 中保存的 mnt_root 信息, 即可得到下一个设备的 dentry, 通过保存的 mnt_sb 可以得到下一级设备的超级块, 通过替换当前身为挂在点的dentry为 mnt_root, 即走到了下一个设备