c - Linux 守护进程似乎挂在“recvfrom”,发现进程 procfs 网络损坏且无法访问
问题描述
我有一个长时间运行的 linux 守护程序,它在端口 65445 上创建了一个“非阻塞”套接字绑定,等待 UDP 数据包。它可以在大部分时间工作。
现在,我遇到了一个问题,该进程在一段时间后变为“D”(不确定是哪条消息导致它,但可以肯定的是,守护进程大部分时间都可以正确处理此类消息,只是在某个随机点,它失败了)
在这个阶段,该进程没有任何信号,所以我不能杀死它,转储内核堆栈:
Kernel Status:
[<ffffffff80385ff3>] number.isra.2+0x2d3/0x300
[<ffffffff802e0228>] address_space_init_once+0x88/0x120
[<ffffffff802e0200>] address_space_init_once+0x60/0x120
[<ffffffff802df880>] inode_wait+0x0/0x10
[<ffffffff802df889>] inode_wait+0x9/0x10
[<ffffffff802df880>] inode_wait+0x0/0x10
[<ffffffff80275dc0>] wake_bit_function+0x0/0x30
[<ffffffff802e0abd>] iget_locked+0x11d/0x180
[<ffffffff8030e1f0>] proc_get_inode+0x10/0xf0
[<ffffffff80313555>] proc_lookup_de+0x75/0xf0
[<ffffffff802d31bc>] d_alloc_and_lookup+0x3c/0x90
[<ffffffff802deeee>] d_lookup+0x2e/0x60
[<ffffffff802d3ea6>] do_lookup+0x296/0x3a0
[<ffffffff802ddcee>] dput+0x1e/0x190
[<ffffffff802d49eb>] link_path_walk+0x12b/0x850
[<ffffffff802dddb2>] dput+0xe2/0x190
[<ffffffff802d7437>] path_openat+0xb7/0x370
[<ffffffff802b4cfe>] tlb_finish_mmu+0xe/0x50
[<ffffffff802d7824>] do_filp_open+0x44/0xb0
[<ffffffff802e2905>] alloc_fd+0x45/0x130
[<ffffffff802c8a5c>] do_sys_open+0xec/0x1d0
[<ffffffff805a8afb>] system_call_fastpath+0x16/0x1b
[<ffffffffffffffff>] 0xffffffffffffffff
说明procfs有问题,经过进一步排查,发现这个进程的procfs的net目录已经损坏,我什至做不到ls /proc/*pid*/net
,bash也挂在那里。
我缩小了进程可能会挂在“recvfrom”上的范围,因为它是一个非阻塞套接字,所以我无法理解,我的部分代码如下:
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fd < 0) {
return ret;
}
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, DEV, sizeof(DEV))
< 0) {
goto Exit;
}
rt = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char *)&sock_buf, sizeof(sock_buf));
if (rt < 0) {
goto Exit;
}
rt = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char *)&sock_buf, sizeof(sock_buf));
if (rt < 0) {
goto Exit;
}
val = fcntl(fd, F_GETFL, 0);
if (val < 0)
return -1;
if (val & O_NONBLOCK)
return 0;
val |= O_NONBLOCK;
fcntl(fd, F_SETFL, val);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET, addr.sin_port = PORT;
addr.sin_addr.s_addr = INADDR_ANY;
if (bind(fd, (void *)&addr, sizeof(addr)) < 0) {
goto Exit;
}
我在 epoll 中添加了这个套接字
struct epoll_event e;
e.events = EPOLLIN;
e.data.ptr = comm_handle;
rc = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &e);
有事件时接收数据包:
socklen_t from_len = sizeof(struct sockaddr_in);
memset(recv_buf, 0, 65000);
len = recvfrom(e->fd, recv_buf, 65000, 0, (struct sockaddr *)&from, &from_len);
if (len <= 0) {
return -1;
}
解决方案
推荐阅读
- android - 如何在单个子滚动视图颤动中使用列
- ide - 如何在pycharm中粘贴多行文本?
- python - 为什么`@property def x: return x`会导致Python崩溃?
- python - 如何逐个字符显示标签文本?
- angular - 使用 CLI 在 Firebase 上部署 Angular 站点(免费)
- google-apps-script - 有没有办法使用谷歌脚本函数批准 =ImportRange(url,range) ?
- f# - 可从回调方法观察到
- javascript - React Context Api Provider Component 在页面重新加载时丢失状态
- node.js - 使用 node-fetch 创建图像 blob
- curl - curl命令中-H,-d等的意义是什么