在内核中,对socket实现了一种虚拟的文件系统(VFS):socketfs。和其它一般文件系统不同,它不能被mount,没有挂载点,而是通过一个静态变量来引用:
[ net/socket.c ]
static struct vfsmount *sock_mnt __read_mostly;
按照内核要求,定义一个结构来描述文件系统类型,然后在初始化时进行注册。
* 包含文件系统名字:sockfs
* 创建super_block函数:sockfs_mount
* 删除super_block函数:kill_anon_super
*/
static struct file_system_type sock_fs_type = {
.name = "sockfs",
.mount = sockfs_mount,
.kill_sb = kill_anon_super,
};
sockfs_mount在安装文件系统(如:mount)时被调用:
/* 创建super_block函数
*/
static struct dentry *sockfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data)
{
/* 创建super block
* 根目录名称为 socket:
* 根目录对应的inode号为1
*/
return mount_pseudo(fs_type, "socket:", &sockfs_ops, &sockfs_dentry_operations, SOCKFS_MAGIC);
}
在创建super block时,会将两个结构与其绑定,一个用于super block的操作,一个用于目录的操作:
/* contains the super block operations that sockfs supports.
*/
static const struct super_operations sockfs_ops = {
.alloc_inode = sock_alloc_inode,
.destroy_inode = sock_destroy_inode,
.statfs = simple_statfs,
};
static const struct dentry_operations sockfs_dentry_operations = {
.d_dname = sockfs_dname,
};
当新建一个socket时,会有一个文件与其对应,这个文件的名称由sockfs_dname来创建:
/*
* sockfs_dname() is called from d_path().
*/
static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen)
{
/* ls -l /proc/1929/fd
* lrwx------ 1 root root 64 2015-04-07 10:50 93 -> socket:[33107]
*/
return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]", dentry->d_inode->i_ino);
}
有了文件名称(文件名称都保存在目录文件中),还要创建一个对应的inode,这样才能对其进行读写操作。为此,内核提供了一个缓冲池:
/* socket的inode节点的缓冲池
*/
static struct kmem_cache *sock_inode_cachep __read_mostly;
/* 初始化缓冲池,缓冲池中的节点为socket_alloc
*/
static int init_inodecache(void)
{
sock_inode_cachep = kmem_cache_create("sock_inode_cache",
sizeof(struct socket_alloc),
0,
(SLAB_HWCACHE_ALIGN |
SLAB_RECLAIM_ACCOUNT |
SLAB_MEM_SPREAD),
init_once);
if (sock_inode_cachep == NULL)
return -ENOMEM;
return 0;
}
static void init_once(void *foo)
{
struct socket_alloc *ei = (struct socket_alloc *)foo;
inode_init_once(&ei->vfs_inode);
}
struct socket_alloc {
struct socket socket;
struct inode vfs_inode;
};
然后来看分配inode的函数:
static struct inode *sock_alloc_inode(struct super_block *sb)
{
struct socket_alloc *ei;
struct socket_wq *wq;
/* 从缓冲池中分配一个socket_alloc结构
*/
ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL);
if (!ei)
return NULL;
/* 分配等待队列结构
* 初始化后,将其赋值给ei->socket.wq
*/
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
*/
ei->socket.state = SS_UNCONNECTED;
ei->socket.flags = 0;
ei->socket.ops = NULL;
ei->socket.sk = NULL;
ei->socket.file =