说一说packet poll 错误掩码的一个bug tcp udp packet poll细节有所不同 处理时需要注意
阅读原文时间:2023年07月08日阅读:1

今天处理一个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 清除数据

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章