天天看點

核心中的UDP socket流程(4)——sock_create

核心中的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已經完結。

繼續閱讀