在之前的文章中,我们介绍了VFS、VFS与进程模块之间的代码分析,也分析了devtmpfs文件系统。
本次我们介绍socketfs,说明下socketfs与vfs之间的关联。
在分析VFS以及分析devtmpfs时,其文件系统变量file_system_type->mount接口实现超级块的创
建以及根目录相关的
dentry、inode的创建,在root_inode的i_op接口中,实现了文件及目录inode创建的接口(i_op->mkdir实现目录的创建、i_op->create实现文件的创建)。而针对socket而言,其并不需要创建真实的文件,因此,其root_inode的i_op接口中并没有mkdir、create接口,其主要将进程描述符的struct file类型的指针与socket相关的结构体关联。
关于sockfs,主要分析如下几个方面的内容:
一、sockfs文件系统类型的定义、注册及挂载
二、sockfs相关的结构体
三、socket fd创建的过程
四、socket相关的系统调用简要介绍
sockfs文件系统类型的定义及注册
针对sockfs,其在sock_init接口中,进行文件系统的注册以及挂载操作,sock_init的接口流程图如下:
通过调用register_filesystem实现文件系统的注册(文件系统的注册之前文章中已经介绍过,可在此处查看)。
其中sockfs文件系统的定义如下,其mount接口为sockfs_mount
static struct file_system_type sock_fs_type = {
.name = "sockfs",
.mount = sockfs_mount,
.kill_sb = kill_anon_super,
};
针对sockfs,调用kern_mount进行sockfs的挂载操作,而kern_mount通过调用vfs_kern_mount进行挂载(但没有调用do_add_mount,将该sockfs挂载到具体目录中,因sockfs无需挂载具体目录)。在vfs_kern_mount->mount_fs->type->mount时,即调用sockfs_mount接口,进行超级块、根root、根dentry相关的创建及初始化操作。如下接口定义,其中sockfs_ops为sockfs的超级块变量相关的操作接口,而sockfs_dentry_operations为sockfs的根dentry的操作接口。
static struct dentry *sockfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
return mount_pseudo(fs_type, "socket:", &sockfs_ops,
&sockfs_dentry_operations, SOCKFS_MAGIC);
}
socketfs 超级块的操作接口,主要包括:
- inode节点的创建接口sock_alloc_inode;
- inode节点的删除接口sock_destroy_inode;
- 文件系统的状态获取接口simple_statfs,可获取文件系统的类型、块大小、文件系统名称大小等
static const struct super_operations sockfs_ops = {
.alloc_inode = sock_alloc_inode,
.destroy_inode = sock_destroy_inode,
.statfs = simple_statfs,
};
struct socket_alloc {
struct socket socket;//struct socket socket变量,用于表示socketfs模块相关的变量,根据该变量可完成对socket链接的建立、数据收发等操作。
struct inode vfs_inode;//inode节点变量
};
下面稍微说明下alloc_inode接口,在介绍该接口之前引入结构体struct socket_alloc,该结构体中包含了vfs模块的inode和socket模块的socket变量,可以说该变量链接了VFS与SOCKETFS模块。
下面我们分析下sock_alloc_inode函数,该函数也就是创建struct socket_alloc类型的指针变量,并对该变量中的inode与socket变量进行初始化,具体功能为:
1.初始化socket变量的状态、flag、ops、sk、file等成员变量;
2.初始化socket的等待队列成员变量wq
static struct inode *sock_alloc_inode(struct super_block *sb)
{
struct socket_alloc *ei;
struct socket_wq *wq;
ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);
if (!ei)
return NULL;
wq = kmalloc(sizeof(*wq), GFP_KERNEL);
if (!wq) {
kmem_cache_free(sock_inode_cachep, ei);
return NULL;
}
init_waitqueue_head(&wq->wait);
wq->fasync_list = NULL;
RCU_INIT_POINTER(ei->socket.wq, wq);
ei->socket.state = SS_UNCONNECTED;
ei->socket.flags = 0;
ei->socket.ops = NULL;
ei->socket.sk = NULL;
ei->socket.file = NULL;
return &ei->vfs_inode;
}
而针对dentry的处理操作接口sockfs_dentry_operations,则提供了sockfs_dname接口,该接口用于生成dentry的名称
static const struct dentry_operations sockfs_dentry_operations = {
.d_dname = sockfs_dname,
};
本小节主要介绍socketfs文件系统的注册,并介绍了socketfs的inode节点的创建等内容,介于我们之前已分析了文件系统注册的接口,因此针对socketfs文件系统的注册分析,相对来说简单了许多。