• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            隨筆-159  評論-223  文章-30  trackbacks-0
               接上篇初始化與創建,本篇闡述Socket操作和銷毀兩部分的實現。

            Socket操作
               系統調用read(v)、write(v)是用戶空間讀寫socket的一種方法,為了弄清楚它們是怎么通過VFS將請求轉發到特定協議的實現,下面以read為例(write同理),并假定文件描述符對應的是IPv4 TCP類型的socket,來跟蹤它的執行流程。首先來看下sys_read的代碼,定義在fs/read_write.c中。
             1SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
             2{
             3    struct file *file;
             4    ssize_t ret = -EBADF;
             5    int fput_needed;
             6
             7    file = fget_light(fd, &fput_needed);
             8    if (file) {
             9        loff_t pos = file_pos_read(file);
            10        ret = vfs_read(file, buf, count, &pos);
            11        
            12    }

            13
            14    return ret;
            15}
               先調用fget_light得到fd對應的file,再調用vfs_read。接著跟蹤vfs_read的代碼,定義在fs/read_write.c中。
             1ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
             2{
             3    ssize_t ret;
             4    
             5    ret = rw_verify_area(READ, file, pos, count);
             6    if (ret >= 0{
             7        count = ret;
             8        if (file->f_op->read)
             9            ret = file->f_op->read(file, buf, count, pos);
            10        else
            11            ret = do_sync_read(file, buf, count, pos);
            12        
            13    }

            14
            15    return ret;
            16}
               在上篇Socket創建一節已知,因為sockfs_file_ops沒有定義read(即read指針為空),所以這兒實際調用了do_sync_read,繼續跟蹤它的代碼,定義在fs/read_write.c中。
             1ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
             2{
             3    struct iovec iov = { .iov_base = buf, .iov_len = len };
             4    struct kiocb kiocb;
             5    ssize_t ret;
             6
             7    
             8    for (;;) {
             9        ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
            10        if (ret != -EIOCBRETRY)
            11            break;
            12        wait_on_retry_sync_kiocb(&kiocb);
            13    }

            14
            15    if (-EIOCBQUEUED == ret)
            16        ret = wait_on_sync_kiocb(&kiocb);
            17    *ppos = kiocb.ki_pos;
            18    return ret;
            19}
               顯而易見,這兒調用到了f_op->aio_read,使用異步讀來實現同步讀,若異步讀沒有完成,則調用wait_on_sync_kiocb等待。由上篇Socket創建一節可知sockfs_file_ops的aio_read設為sock_aio_read函數,定義在net/socket.c中,至此sys_read的實現完成了前一半(操作對象是file)而進入后一半(操作對象是socket),即socket層的實現。
               在socket層跟蹤sock_aio_read,可以得到最后調用的是sock->ops->recvmsg,由于socket類型為IPv4 TCP,因此sock->ops在socket創建過程中被設為inet_stream_ops,定義在net/ipv4/af_inet.c中。
            1const struct proto_ops inet_stream_ops = {
            2    .family    =  PF_INET,
            3    
            4    .release   =  inet_release,
            5    
            6    .recvmsg  =  sock_common_recvmsg,
            7    
            8}
            ;
               從上可知recvmsg設為sock_common_recvmsg,跟蹤它的代碼,定義在net/core/sock.c中。  
             1int sock_common_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags)
             2{
             3    struct sock *sk = sock->sk;
             4    int addr_len = 0;
             5    int err;
             6
             7    err = sk->sk_prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT,flags & ~MSG_DONTWAIT, &addr_len);
             8    
             9    return err;
            10}
               struct sock表示套接字的網絡接口層,它的成員sk_prot表示網絡協議塊,在這它對應tcp_prot結構,定義在net/ipv4/tcp_ipv4.c中,由此可見進入到特定協議的實現。
            1struct proto tcp_prot = {
            2    .name            = "TCP",
            3    
            4    .close   =  tcp_close,
            5    
            6    .recvmsg  =  tcp_recvmsg,
            7    
            8}
            ;
               recvmsg設為tcp_recvmsg,至此跟蹤結束。對于sys_readv的實現,調用的是vfs_readv,后面的過程和sys_read相同,總結核心調用鏈如下圖:
               由此可知,sockfs_file_ops只須實現aio_read,就能支持普通和聚集兩種方式的讀操作。為了對比,這里也給出Berkeley Sockets API中recv的核心調用鏈如下圖:
               顯而易見,recv內部實現調用的是sys_recvfrom,它沒有經過VFS,而是先調用sock_lookup_light從fd得到socket,再調用sock_recvmsg,后面的流程和recv就是一樣的了。

            Socket銷毀
               Socket操作既可以調用文件IO,也可以調用Berkeley Sockets API。但銷毀不同,系統調用close是用戶空間銷毀socket的唯一方法,它定義在fs/open.c中。
             1SYSCALL_DEFINE1(close, unsigned int, fd)
             2{
             3    struct file * filp;
             4    struct files_struct *files = current->files;
             5    struct fdtable *fdt;
             6    int retval;
             7
             8    spin_lock(&files->file_lock);
             9    fdt = files_fdtable(files);
            10    
            11    filp = fdt->fd[fd];
            12    
            13    rcu_assign_pointer(fdt->fd[fd], NULL);
            14    FD_CLR(fd, fdt->close_on_exec);
            15    __put_unused_fd(files, fd);
            16    spin_unlock(&files->file_lock);
            17    retval = filp_close(filp, files);
            18    
            19}
               首先從fd獲取對應的file,若file非空則設置進程描述符數組對應項為空,并將fd從exec時關閉的文件描述符鏈表和打開的文件描述符鏈表中移除;最后調用filp_close,跟蹤它的代碼,定義在fs/open.c中。
             1int filp_close(struct file *filp, fl_owner_t id)
             2{
             3    int retval = 0;
             4
             5    if (!file_count(filp)) {
             6        printk(KERN_ERR "VFS: Close: file count is 0\n");
             7        return 0;
             8    }

             9
            10    if (filp->f_op && filp->f_op->flush)
            11        retval = filp->f_op->flush(filp, id);
            12
            13    dnotify_flush(filp, id);
            14    locks_remove_posix(filp, id);
            15    fput(filp);
            16    return retval;
            17}
               首先判斷file的引用計數,若為0則打印一個錯誤日志(說明這是一個bug,因為file已經被釋放)并返回;由于sockfs_file_ops中的flush沒有定義即為空,因此跳過;dnotify_flush用于釋放任何相關的dnotify(一種文件監控機制)資源,locks_remove_posix用于清除文件鎖相關的資源,由于socket對應的inode沒有使用文件鎖,因此它什么也沒做。最后調用fput來釋放file,定義在fs/file_table.c中。
            1void fput(struct file *file)
            2{
            3    if (atomic_long_dec_and_test(&file->f_count))
            4        __fput(file);
            5}
               先遞減引用計數,若為0則調用__fput釋放file,它會調用到sockfs_file_ops定義的release函數即sock_close,它是sock_release的包裝函數,sock_release定義在net/socket.c中。
             1void sock_release(struct socket *sock)
             2{
             3    if (sock->ops) {
             4        struct module *owner = sock->ops->owner;
             5
             6        sock->ops->release(sock);
             7        sock->ops = NULL;
             8        module_put(owner);
             9    }

            10    if (sock->fasync_list)
            11        printk(KERN_ERR "sock_release: fasync list not empty!\n");
            12
            13    percpu_sub(sockets_in_use, 1);
            14    if (!sock->file) {
            15        iput(SOCK_INODE(sock));
            16        return;
            17    }

            18    sock->file = NULL;
            19}
                      
               先調用ops->release即特定協議的釋放操作,對于IPv4 TCP,就是inet_stream_ops中定義的inet_release函數,它又會調用到tcp_prot中定義的close即tcp_close;對于關聯inode的釋放,這里要分2種情況:如果sock->file為空,就調用iput釋放,否則返回到__fput中,會調用dput釋放dentry,而dentry又關聯著inode,最終調用iput釋放inode;當最后一個iput被調用時,sockfs_ops中定義的sock_destroy_inode就會被調用,歸還由sock_alloc_inode分配的struct socket_alloc對象到SALB緩存中。總結核心調用鏈如下圖:
               
               在上篇初始化一節,我們已知sockfs文件系統被裝載,然而實際上沒有卸載它的方式。由于TCP/IP協議棧和sockfs被靜態編譯到內核中,而不是一個內核模塊。因此沒必要提供一個卸載函數,sockfs偽文件系統在啟動到關閉期間,總是被裝載著的。
            posted on 2015-05-03 16:55 春秋十二月 閱讀(5268) 評論(0)  編輯 收藏 引用 所屬分類: Network
            狠狠色丁香久久婷婷综合图片| 97久久香蕉国产线看观看| 亚洲人AV永久一区二区三区久久| 国产精品久久久久天天影视| 久久精品综合网| 国产精品无码久久四虎| 久久er热视频在这里精品| 久久人人爽人人爽人人片AV不 | 99久久免费国产特黄| 久久久久久精品免费免费自慰| 日韩一区二区三区视频久久| 亚洲AⅤ优女AV综合久久久| 国产成人久久精品麻豆一区 | 亚洲美日韩Av中文字幕无码久久久妻妇 | 久久中文字幕视频、最近更新| 四虎亚洲国产成人久久精品| 久久精品夜色噜噜亚洲A∨ | 要久久爱在线免费观看| 久久伊人影视| 亚洲精品午夜国产va久久| 女人高潮久久久叫人喷水| 一本色道久久88综合日韩精品| 久久婷婷五月综合97色直播| 久久国产精品无码一区二区三区| 久久99精品国产99久久| 麻豆精品久久精品色综合| 久久免费国产精品一区二区| 日本亚洲色大成网站WWW久久 | 奇米综合四色77777久久| 99久久精品免费看国产一区二区三区| 狠狠综合久久综合88亚洲| 久久香蕉超碰97国产精品| 69久久夜色精品国产69| 久久精品国产影库免费看| 国产成人无码精品久久久久免费| 亚洲婷婷国产精品电影人久久| 国产午夜免费高清久久影院| 午夜福利91久久福利| 精品久久久无码人妻中文字幕| 久久综合综合久久97色| 婷婷久久综合九色综合绿巨人 |