🚀

socket(2)でsocketが生成されるまで

2023/05/02に公開

概要

古いバージョンではkmem_cache_allocでsocketを、new_inode_pseudoで対応するinodeを確保していた。
現在のバージョン(6.3)ではnew_inode_pseudoでinodeを確保する際にsocket用の領域も一緒に確保している。

socketシステムコールの定義は以下の通り。

SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
{
         return __sys_socket(family, type, protocol);
}

socketを割り当てる部分は以下のコードです。

int __sock_create(struct net *net, int family, int type, int protocol,
			struct socket **res, int kern)
{
	...
	sock = sock_alloc();
	...
}
struct socket *sock_alloc(void)
{
	struct inode *inode;
	struct socket *socket;
	
	inode = new_inode_pseudo(sock_mnt->mnt_sb);
	...
	sock = SOCKET_I(inode);
	...
}

ソケットのsb(スーパーブロック)を渡してinodeを確保し、SOCKET_Iでinodeからsocketのアドレスを計算しています。つまり、

struct socket_alloc {
	struct socket socket;
	struct inode vfs_inode;
};

inode確保の際に上記の構造体としてsocket用の領域も含めて確保して、socketのアドレスを計算しています。

struct inode *new_inode_pseudo(struct superblock *sb)
{
	struct inode *inode = alloc_inode(sb);
	...
}
struct static inode *alloc_inode(struct super_block *sb)
{
	const struct super_operations *ops = sb->s_op;
	...
		inode = ops->alloc_inode(sb);
	...
}

inode確保に使うnew_inode_pseudo関数ですが、内部ではsb(スーパーブロック)に登録されているalloc_inodeを使っています。

sock_mnt->mnt_sbの設定を見ると、

static int sockfs_init_fs_context(struct fs_context *fc)
{
	...
		ctx->ops = &sockfs_ops;
	...
}
static const struct super_operations sockfs_ops = {
	.alloc_inode    = sock_alloc_inode,
	.free_inode     = sock_free_inode,
	.statfs         = simple_statfs,
 };

ということで、sock_alloc_inodeがsocket用のinode確保時に呼ばれていることが分かります。

static struct inode *sock_alloc_inode(struct super_block *sb)
{
       struct socket_alloc *ei;
       ei = alloc_inode_sb(sb, sock_inode_cachep, GFP_KERNEL);
   ...
   return &ei->vfs_inode;
}

上記から、socketとinodeが同時に確保されていることが分かります。

Discussion