说一说packet poll 错误掩码的一个bug tcp udp packet poll细节有所不同 处理时需要注意

今天处理一个cpu标高的bug,原因:在poll 返回后将error事件当做POLLIN事件处理,fd 一直都在唤醒线程处理,但是rcv的时候没有数据;

unsigned int datagram_poll(struct file *file, struct socket *sock,
               poll_table *wait)
{
    struct sock *sk = sock->sk;
    unsigned int mask;

    sock_poll_wait(file, sk_sleep(sk), wait);
    mask = 0;

    /* exceptional events? */
    if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
        mask |= POLLERR;
    if (sk->sk_shutdown & RCV_SHUTDOWN)
        mask |= POLLRDHUP | POLLIN | POLLRDNORM;
    if (sk->sk_shutdown == SHUTDOWN_MASK)
        mask |= POLLHUP;
static unsigned int packet_poll(struct file *file, struct socket *sock,
                poll_table *wait)
{
    struct sock *sk = sock->sk;
    struct packet_sock *po = pkt_sk(sk);
    unsigned int mask = datagram_poll(file, sock, wait);

    spin_lock_bh(&sk->sk_receive_queue.lock);
    if (po->rx_ring.pg_vec) {
        if (!packet_previous_rx_frame(po, &po->rx_ring,
            TP_STATUS_KERNEL))
            mask |= POLLIN | POLLRDNORM;
    }

 

从代码中可以看到(sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)  只要满足一个条件就会唤醒进程,但是由于sk_error_queue 的数据一直都没有清楚,所以会导致一直唤醒进程。但是mmap-packet读取数据时,又没有数据

那么怎么处理呢?

目前简单的处理方式为:在rcvmsg时 带上MSG_ERRQUEUE  主动收取错误报文

或者

case SO_ERROR:
        v.val = -sock_error(sk);
        if (v.val == 0)
            v.val = xchg(&sk->sk_err_soft, 0);
        break;

//使用getsockopt  获取错误标志

case IP_RECVERR:
        inet->recverr = !!val;
        if (!val)
            skb_queue_purge(&sk->sk_error_queue);
        break;

//使用 ip_setsockopt  清除数据

 

posted @ 2020-05-07 20:19  codestacklinuxer  阅读(361)  评论(0编辑  收藏  举报