内核中的UDP socket流程(4)——sock_create
作者:gfree.wind@gmail.com
又懒了2天,继续sock_create
/* Compatibility.
This uglymoron is moved from INET layer to here to avoid
deadlock in module load.
*/
if (family == PF_INET && type == SOCK_PACKET) {
static int warned;
if (!warned) {
warned = 1;
printk(KERN_INFO "%s uses obsolete (PF_INET,SOCK_PACKET)\n",
current->comm);
}
family = PF_PACKET;
}
err = security_socket_create(family, type, protocol, kern);
if (err)
return err;
|
首先是对PF_INET,SOCK_PACKET的兼容性处理。
security_socket_create函数是一个空函数,省略。
下面是去申请一个socket node,我们需要进入sock_alloc中看如何分配的节点。
/*
* Allocate the socket and allow the family to set things up. if
* the protocol is 0, the family is instructed to select an appropriate
* default.
*/
sock = sock_alloc();
if (!sock) {
if (net_ratelimit())
printk(KERN_WARNING "socket: no more sockets\n");
return -ENFILE; /* Not exactly a match, but its the
closest posix thing */
}
|
下面是sock_alloc的代码
static struct socket *sock_alloc(void) {
struct inode *inode;
struct socket *sock;
inode = new_inode(sock_mnt->mnt_sb);
if (!inode)
return NULL;
sock = SOCKET_I(inode);
kmemcheck_annotate_bitfield(sock, type);
inode->i_mode = S_IFSOCK | S_IRWXUGO;
inode->i_uid = current_fsuid();
inode->i_gid = current_fsgid();
percpu_add(sockets_in_use, 1);
return sock; } |
其中sock_mnt是一个全局变量,它在sock_init中被初始化的。并挂载到VFS层上。在sock_alloc函数中,首先是从sock_mnt->mnt_sb即socket的super block中申请一个节点。然后通过SOCKET_I宏,取得inode对应的socket的地址。
这里之所以这样做的,原因是因为,inode的分配是统一的,但是每个inode的用途是不一样的。
在socket中,申请的inode的节点,实际上对应的结构应该为下面这个结构。
struct socket_alloc {
struct socket socket;
struct inode vfs_inode; }; |
new_inode中实际上是申请了一个struct socket_alloc的地址,但是返回的确是socket_all->vs_inode的地址。所以在这里需要使用SOCKET_I宏,来从inode地址中,得到socket的地址。
后面的宏kmemcheck_annotate_bitfield是一个内存检查,略过。然后,设置inode的mode,uid,gid。
percpu_add(sockets_in_use, 1)是增加sockets_in_use的统计计数——这个计数变量是每个cpu的私有变量。
然后,我们就回到__sock_create。
rcu_read_lock();
pf = rcu_dereference(net_families[family]);
err = -EAFNOSUPPORT;
if (!pf)
goto out_release;
/*
* We will call the ->create function, that possibly is in a loadable
* module, so we have to bump that loadable module refcnt first.
*/
if (!try_module_get(pf->owner))
goto out_release;
/* Now protected by module ref count */
rcu_read_unlock(); |
通过RCU机制,获得pf(family)对应的net_families中的指针。
下面通过调用函数指针调用用户指定family的函数去创建socket。
err = pf->create(net, sock, protocol, kern);
if (err 0)
goto out_module_put;
|
对于TCP/IP来说,family是PF_INET。
现在又需要跳到文件linux/net/ipv4/af_inet.c,下面是PF_INET对应的协议域定义
static const struct net_proto_family inet_family_ops = {
.family = PF_INET,
.create = inet_create,
.owner = THIS_MODULE, };
|
所以对于对于TCP/IP的socket来说,sock_create中这里的create函数实际上指向的是inet_create——这个函数明天再说,继续sock_create的代码。
/*
* Now to bump the refcnt of the [loadable] module that owns this
* socket at sock_release time we decrement its refcnt.
*/
if (!try_module_get(sock->ops->owner))
goto out_module_busy;
/*
* Now that we're done with the ->create function, the [loadable]
* module can have its refcnt decremented
*/
module_put(pf->owner);
err = security_socket_post_create(sock, family, type, protocol, kern);
if (err)
goto out_sock_release;
*res = sock;
return 0;
|
这几行代码的注释已经很清楚,到此sock_create已经完结。