在“VFS对象”博文中所描述的关于VFS的很多方法在Ext2都有相应的实现。因为对所有的方法都进行讨论需要整整一本书,因此我们仅仅简单地回顾一下在Ext2中所实现的方法。一旦你真正搞明白了磁盘和内存数据结构,你就应当能理解实现这些方法的Ext2函数的代码。
1 Ext2超级块的操作
在“Ext2的索引节点对象”我们已经分析了Ext2超级块的操作之一:ext2_alloc_inode,这里在对Ext2超级块的操作做一个综合性的总结。很多VFS超级块操作在Ext2中都有具体的实现,这些方法为alloc_inode、destroy_inode、read_inode、write_inode、delete_inode、put_super、write_super、statfs、remount_fs和clear_inode。超级块方法的地址存放在ext2_sops指针数组:
static struct super_operations ext2_sops = {
.alloc_inode = ext2_alloc_inode,
.destroy_inode = ext2_destroy_inode,
.read_inode = ext2_read_inode,
.write_inode = ext2_write_inode,
.put_inode = ext2_put_inode,
.delete_inode = ext2_delete_inode,
.put_super = ext2_put_super,
.write_super = ext2_write_super,
.statfs = ext2_statfs,
.remount_fs = ext2_remount,
.clear_inode = ext2_clear_inode,
.show_options = ext2_show_options,
#ifdef CONFIG_QUOTA
.quota_read = ext2_quota_read,
.quota_write = ext2_quota_write,
#endif
};
2 Ext2索引节点的操作
一些VFS索引节点的操作在Ext2中都有具体的实现,这取决于索引节点所指的文件类型。
如果文件类型是普通文件,则对应inode的方法存放在ext2_file_inode_operations表中:
struct inode_operations ext2_file_inode_operations = {
.truncate = ext2_truncate,
#ifdef CONFIG_EXT2_FS_XATTR
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = ext2_listxattr,
.removexattr = generic_removexattr,
#endif
.setattr = ext2_setattr,
.permission = ext2_permission,
.fiemap = ext2_fiemap,
};
注意,普通文件的inode操作有很多没有实现VFS索引节点所规定的那些动作。
如果文件类型是目录,那么对应inode的方法存放在ext2_dir_inode_operations表中:
struct inode_operations ext2_dir_inode_operations = {
.create = ext2_create,
.lookup = ext2_lookup,
.link = ext2_link,
.unlink = ext2_unlink,
.symlink = ext2_symlink,
.mkdir = ext2_mkdir,
.rmdir = ext2_rmdir,
.mknod = ext2_mknod,
.rename = ext2_rename,
#ifdef CONFIG_EXT2_FS_XATTR
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = ext2_listxattr,
.removexattr = generic_removexattr,
#endif
.setattr = ext2_setattr,
.permission = ext2_permission,
};
如果文件类型是符号链接,那么实际上是有两种符号链接的:快速符号链接(路径名全部存放在索引节点内)与普通符号链接(较长的路径名)。因此,有两套索引节点操作,分别存放在ext2_fast_symlink_inode_operations和ext2_symlink_inode_operations表中:
struct inode_operations ext2_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = page_follow_link_light,
.put_link = page_put_link,
#ifdef CONFIG_EXT2_FS_XATTR
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = ext2_listxattr,
.removexattr = generic_removexattr,
#endif
};
struct inode_operations ext2_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.follow_link = ext2_follow_link,
#ifdef CONFIG_EXT2_FS_XATTR
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
.listxattr = ext2_listxattr,
.removexattr = generic_removexattr,
#endif
};
如果索引节点指的是一个字符设备文件、块设备文件或管道文件,那么这种索引节点的操作部依赖于具体的文件系统,其分别位于chrdev_inode_operations、blkdev_inode_operations和fifo_inode_operations表中。这些数据结构在新的内核版本中已经淘汰了,我们就不去详细描述他们了。
3 Ext2的文件操作
针对Ext2文件系统特定的文件操作,其实现VFS文件对象的具体方法地址存放在ext2_file_operations表中:
const struct file_operations ext2_file_operations = {
.llseek = generic_file_llseek,
.read = generic_file_read,
.write = generic_file_write,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
.ioctl = ext2_ioctl,
.mmap = generic_file_mmap,
.open = generic_file_open,
.release = ext2_release_file,
.fsync = ext2_sync_file,
.readv = generic_file_readv,
.writev = generic_file_writev,
.sendfile = generic_file_sendfile,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
};
我们看到,大部分方法都有generic字符,说明这些方法不仅只被ext2文件系统使用,而且是个很通用的方法,如果你有兴趣去看看ext3_file_operations或ext4_file_operations你会发现,他们也大量使用了这些通用的方法。Ext2最主要的读写文件方法的read和write方法分别通过generic_file_read和generic_file_write函数实现。这两个函数我们会在以后的博文中重点讨论他们。