fdbased: 为每个分发器创建的 eventfd 从不关闭
说明
每个 " 基于fd " 的端点都会产生一个事件fd,当端点从堆栈中取出时,它永远不会关闭。 在反复地创建并去除端点的过程中,被泄露的fd最终击中了"RLIMIT NOFILE",而下个端点无法构造:
创建 InboundDispatcher (. ) = 新的ReadV Dispatcher (777,...) = 无法创建事件fd: 太多打开文件我们用 " pkg/tcpip " 作为图书馆遇到这种情况。 ls-l/proc/<pid>/fd'在该点上显示一个aon inode:[eventfd]',每一端点被创建。
这似乎来自新ReadV Dispatcher'(和revmmsg/包-mmap变体),称为stopfd'。 New()`,创建事件fd。 "StopFD.Stop ()"给事件fd写信,但从未关闭过它:
停止.停止FD有新'和停止',没有`关闭'fdbased.endpoint.Close()'为tack'。 LinkEndpoint"文档'Close'为"当端点被从堆栈中去掉时所叫",而"nic.remove"确实在"Attach(nil)"后称之为"""",所以它是正确的地方,但它无所作为.- 调度员的
释放()'释放iovec缓冲器并关闭处理器管理器,但不要碰嵌入式停止FD'。
xdp.endpoint'还在New'中创建了StopFD',并有一个空的Close ()'。
在看时,我发现Sharedmem'也拥有一个活动,并在工人离开后在wait()'关闭。 就我所知,基于fd和xdp是唯一的链接端点,它们会分配自己的fd,永远不放出. 我想这还没有出现,因为Runc一次在靴子上创建了它的终点,并把它们保存到沙盒的一生中,所以每个沙盒只有一英尺. 它只有在一个过程中的终点被反复地创建并被摧毁时被咬.
此外,在“RepvMMsg”和“PacketMMap”模式中,实际上每个终点有两个事件fd。 创建 " InboundDispatcher " 无条件建立readVDispatcher ' ,然后取而代之。 第一种从未储存在`E.inbound Dispatchers'中,因此,任何拆卸都达不到它,其处理器管理器已经生产出出它的出行道。 runc默认使用 “ repvMMsg ” , 所以每个沙盒都带有一个孤儿事件fd 和一组孤儿处理器 goroutines 每个链接fd 从靴子中取出。
- 复制步骤
在“/proc/self/fd”的循环和计数中创建并删除端点:
开始 //再生成pkg/tcpip/link/fd基中的事件fd泄漏:每个端点 // 以 fd 创建. 新建, 然后从堆栈中取出 。 //调度员的停止事件fd打开. 主软件包
导入( E) "fmt" (英语). "欧" "弦乐"
"golang.org/x/sys/unix" (英语). “gvisor.dev/gvisor/pkg/tcpip/link/fdbased” (中文(简体) ). “gvisor.dev/gvisor/pkg/tcpip/网络/ipv4” “gvisor.dev/gvisor/pkg/tcpip/stack” (中文(简体) ).
func 计数 Eventfds () int { 条目,错误 := os.ReadDir ("/proc/self/fd") 如果错误 ! = 无 { 恐慌( err) {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? 无:= 0 用于 , e: = 范围条目{ 目标,错误:= os.Readlink ("/proc/self/fd/" + e.Name ()) 如果错误========= 包含( 目标, “ aon inode : [eventfd] ”) { n++ 组合 {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? 返回n {\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢?
func 循环( 模式 fd based) 。 包裹发送模式) . . . . . . .
内容来源: google/gvisor