核心中的UDP socket流程(4)——sock_create作者:[email protected]
又懶了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))
/* 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);
goto out_sock_release;
*res = sock;
return 0;
這幾行代碼的注釋已經很清楚,到此sock_create已經完結。