Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5761978
  • 博文数量: 675
  • 博客积分: 20301
  • 博客等级: 上将
  • 技术积分: 7671
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-31 16:15
文章分类

全部博文(675)

文章存档

2012年(1)

2011年(20)

2010年(14)

2009年(63)

2008年(118)

2007年(141)

2006年(318)

分类: LINUX

2008-03-13 14:23:53

今天在将项目从虚拟机上移植到真实机器上面的时候,发现问题,总是不成功,最后判断是userspace的程序没有向kernel发送消息成功,因为无法触发kernel的行为,但是userspace显示正常。

这个问题好像两个月之前,netlink模块测试的时候遇到过这个问题,当时加上sleep就好了,同样复制这个方法,发现使用usleep(1)就解决问题了。

接下来分析问题的原因,问题锁定在sendmsg上面。

查看sendmsg的返回值,发现是-1,也就是说sendmsg失败了,看errno: ENOBUFS。
       ENOBUFS
              The output queue for a network interface was full.  This generally indicates that the interface has stopped sending, but may be caused  by  transient  conges-
              tion.  (Normally, this does not occur in Linux.  Packets are just silently dropped when a device queue overflows.)

也就是说发送队列占满了,怎么会出现出现这样的问题呢?

追踪sendmsg函数:

sys_sendmsg()
......
    err = -ENOBUFS;

    if (msg_sys.msg_controllen > INT_MAX)
        goto out_freeiov;
    ctl_len = msg_sys.msg_controllen;
    if ((MSG_CMSG_COMPAT & flags) && ctl_len) {
        err = cmsghdr_from_user_compat_to_kern(&msg_sys, sock->sk, ctl, sizeof(ctl));
        if (err)
            goto out_freeiov;

......
out_freectl:
    if (ctl_buf != ctl)   
        sock_kfree_s(sock->sk, ctl_buf, ctl_len);
out_freeiov:
    if (iov != iovstack)
        sock_kfree_s(sock->sk, iov, iov_size);
out_put:
    fput_light(sock->file, fput_needed);
out:      
    return err;
发现在sys_sendmsg中会引用一些msg中的成员变量,一些变量很大导致返回ENOBUFS错误,最终导致no buffer space available。

看我们的userspace代码:

    struct msghdr msg;

    msg.msg_name = (void *)&dest_addr;
    msg.msg_namelen = sizeof(dest_addr);
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

OMG,竟然没有初始化,这样的话,msg.msg_controllen就有可能比较大,导致出现ENOBUFS错误。

解决方法就是初始化msg:
memset(&msg, 0 ,sizeof(msg));

注意:在调试内核相关程序的时候,一定要检查返回值,一定要进行初始化,不要想当然。有些编译器会帮你初始化,但是有些不会,程序员不能够依赖编译器来干活 :-)

参考:



阅读(11780) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~