核心通訊之Netlink源碼分析-使用者核心通訊原理3

來源:互聯網
上載者:User

標籤:互動   刪除   複製   inux   訪問   取資料   tin   系統   cal   

2017-07-06

 

上節主講了使用者層通過netlink和核心互動的詳細過程,本節分析下使用者層接收資料的過程……

有了之前基礎知識的介紹,使用者層接收資料只涉及到一個核心調用readmsg(),

其他的就不多介紹了,不太明白的請參考之前的文章,我們還是重點看下核心究竟在背後做了什麼!該函數在核心對應於read_msg系統調用

SYSCALL_DEFINE3(recvmsg, int, fd, struct msghdr __user *, msg,        unsigned int, flags){    if (flags & MSG_CMSG_COMPAT)        return -EINVAL;    return __sys_recvmsg(fd, msg, flags);}

 沒什麼特殊的,調用了__sys_recvmsg

long __sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags){    int fput_needed, err;    struct msghdr msg_sys;    struct socket *sock;    /*根據找到對應socket結構*/    sock = sockfd_lookup_light(fd, &err, &fput_needed);    if (!sock)        goto out;    err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0);    fput_light(sock->file, fput_needed);out:    return err;}

 這裡主要分為兩部分1、根據傳遞進來的fd找到核心中的socket資料結構。2、調用___sys_recvmsg執行剩餘的工作,前者在發送資料的時候已經進行過介紹,這裡就不再贅述。直接看___sys_recvmsg,該函數比較長我們還是分部來看。

if (MSG_CMSG_COMPAT & flags) {        if (get_compat_msghdr(msg_sys, msg_compat))            return -EFAULT;    } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr)))        return -EFAULT;    if (msg_sys->msg_iovlen > UIO_FASTIOV) {        err = -EMSGSIZE;        if (msg_sys->msg_iovlen > UIO_MAXIOV)            goto out;        err = -ENOMEM;        iov = kmalloc(msg_sys->msg_iovlen * sizeof(struct iovec),                  GFP_KERNEL);        if (!iov)            goto out;    }

 首先自然是擷取頭部msghdr資訊,注意參數中的msghdr指標為使用者空間的地址,所以我們需要在核心中構建一個msghdr,把使用者空間結構的內容拷貝到核心中,如果flag欄位有MSG_CMSG_COMPAT,則直接使用核心指標訪問使用者空間的msghdr的屬性欄位。否則使用copy_from_user把整個結構複製過來。前面文章介紹過msghdr並不直接管理資料,而是通過iov向量。這裡如果msg_sys->msg_iovlen超過UIO_FASTIOV,這種情況還有迴旋的餘地,如果沒有超過UIO_MAXIOV,則在核心分配多出UIO_FASTIOV的iov向量,因為前面已經在核心棧中分配好了UIO_FASTIOV數量的核心iov,接下來的工作就比較簡單,需要把使用者空間iov裡記錄的資訊複製到核心空間的iov中,代碼如下,

uaddr = (__force void __user *)msg_sys->msg_name;    uaddr_len = COMPAT_NAMELEN(msg);    /*修改iov資訊*/    if (MSG_CMSG_COMPAT & flags) {        err = verify_compat_iovec(msg_sys, iov, &addr, VERIFY_WRITE);    } else        err = verify_iovec(msg_sys, iov, &addr, VERIFY_WRITE);    if (err < 0)        goto out_freeiov;    total_len = err;

 接下來略過一些控制檢查就該處理資料了,

cmsg_ptr = (unsigned long)msg_sys->msg_control;    msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT);    if (sock->file->f_flags & O_NONBLOCK)        flags |= MSG_DONTWAIT;    err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys,                              total_len, flags);

 我們分析sock_recvmsg,在快速處理的時候會使用sock_recvmsg_nosec,回想下在發送資料的時候 有個used_address,即如果當前地址和上次發送使用的地址一樣,則調用快速處理函數。這裡也是同樣的道理。在sock_recvmsg中主要調用了__sock_recvmsg繼而調用了__sock_recvmsg_nosec,最終調用到sock->ops->recvmsg,針對netlink,這裡就是netlink_recvmsg,針對該函數拋開現象看本質的話還是挺清晰的,主要分為兩步

1、從指定的sock接收隊列中取出一個skb

2、把skb中的資料複製到使用者空間的記憶體中

前者由skb_recv_datagram函數完成,該函數又調用了__skb_recv_datagram,在該函數中涉及到一個MSG_PEEK標誌,如果flags欄位設定了該標誌,則從接收隊列中取出skb後不會把skb從隊列中刪除,所以這樣就需要另一個參數off來確定本次需要的是哪個skb.如果沒有設定,則得到一個skb後會把skb從隊列中刪除,這樣實際上每次取隊列中的首個就可以了,核心代碼如下。

struct sk_buff_head *queue = &sk->sk_receive_queue;        int _off = *off;        last = (struct sk_buff *)queue;        spin_lock_irqsave(&queue->lock, cpu_flags);        /*遍曆迴圈雙鏈表*/        skb_queue_walk(queue, skb) {            last = skb;            *peeked = skb->peeked;            if (flags & MSG_PEEK) {                if (_off >= skb->len && (skb->len || _off ||                             skb->peeked)) {                    _off -= skb->len;                    continue;                }                skb->peeked = 1;                atomic_inc(&skb->users);            } else                __skb_unlink(skb, queue);            spin_unlock_irqrestore(&queue->lock, cpu_flags);            *off = _off;            return skb;        }

 在擷取到skb之後,下面該複製資料了,具體由skb_copy_datagram_iovec函數完成,完成後更新了下msg->msgname和msg_namelen欄位。看下skb_copy_datagram_iovec複製函數,該函數也比較清晰,但是涉及到skb的組織方式,又稍顯複雜,本節不打算很詳細的講述skb的組織,後面單獨開一節來介紹,該函數主要分為三部分:

1、複製頭部

2、複製分區

3、複製子skb

 該部分內容在詳細介紹skb的時候再做介紹,這樣複製到iov中後,接收過程就完成了,使用者空間就可以正常讀取資料了……

 

以馬內利

參考資料

linux3.10.1核心源碼

 

核心通訊之Netlink源碼分析-使用者核心通訊原理3

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.