userfaultfd内核线程D状态问题排查

问题现象

运维反应机器上出现了很多D状态进程,也kill不掉,然后将现场保留下来进行排查。
在这里插入图片描述

在这里插入图片描述

排查过程

都是内核线程,先看下内核栈D在哪了,发现D在了userfaultfd的pagefault流程。
在这里插入图片描述

uffd知识补充

uffd探究
uffd在firecracker与e2b的架构下使用方式如下:
1.firecracker注册uffd共享给orchestrator,并将guest内存地址空间提交给orchestrator。
2.guest触发缺页,vm-exit出来,创建内核线程通知orchestrator有需要处理的pf请求,然后等待处理。
3.orchestrator会调用ioctl从内存快照文件中将数据写入到对应的内存页中
在这里插入图片描述
查看handle_userfault代码进行分析。

vm_fault_t handle_userfault(struct vm_fault *vmf, unsigned long reason)
{struct vm_area_struct *vma = vmf->vma;struct mm_struct *mm = vma->vm_mm;struct userfaultfd_ctx *ctx;struct userfaultfd_wait_queue uwq;vm_fault_t ret = VM_FAULT_SIGBUS;bool must_wait;unsigned int blocking_state;/** We don't do userfault handling for the final child pid update.** We also don't do userfault handling during* coredumping. hugetlbfs has the special* hugetlb_follow_page_mask() to skip missing pages in the* FOLL_DUMP case, anon memory also checks for FOLL_DUMP with* the no_page_table() helper in follow_page_mask(), but the* shmem_vm_ops->fault method is invoked even during* coredumping and it ends up here.*/if (current->flags & (PF_EXITING|PF_DUMPCORE))goto out;assert_fault_locked(vmf);ctx = vma->vm_userfaultfd_ctx.ctx;if (!ctx)goto out;BUG_ON(ctx->mm != mm);/* Any unrecognized flag is a bug. */VM_BUG_ON(reason & ~__VM_UFFD_FLAGS);/* 0 or > 1 flags set is a bug; we expect exactly 1. */VM_BUG_ON(!reason || (reason & (reason - 1)));if (ctx->features & UFFD_FEATURE_SIGBUS)goto out;if (!(vmf->flags & FAULT_FLAG_USER) && (ctx->flags & UFFD_USER_MODE_ONLY))goto out;/** If it's already released don't get it. This avoids to loop* in __get_user_pages if userfaultfd_release waits on the* caller of handle_userfault to release the mmap_lock.*/if (unlikely(READ_ONCE(ctx->released))) {/** Don't return VM_FAULT_SIGBUS in this case, so a non* cooperative manager can close the uffd after the* last UFFDIO_COPY, without risking to trigger an* involuntary SIGBUS if the process was starting the* userfaultfd while the userfaultfd was still armed* (but after the last UFFDIO_COPY). If the uffd* wasn't already closed when the userfault reached* this point, that would normally be solved by* userfaultfd_must_wait returning 'false'.** If we were to return VM_FAULT_SIGBUS here, the non* cooperative manager would be instead forced to* always call UFFDIO_UNREGISTER before it can safely* close the uffd.*/ret = VM_FAULT_NOPAGE;goto out;}/** Check that we can return VM_FAULT_RETRY.** NOTE: it should become possible to return VM_FAULT_RETRY* even if FAULT_FLAG_TRIED is set without leading to gup()* -EBUSY failures, if the userfaultfd is to be extended for* VM_UFFD_WP tracking and we intend to arm the userfault* without first stopping userland access to the memory. For* VM_UFFD_MISSING userfaults this is enough for now.*/if (unlikely(!(vmf->flags & FAULT_FLAG_ALLOW_RETRY))) {/** Validate the invariant that nowait must allow retry* to be sure not to return SIGBUS erroneously on* nowait invocations.*/BUG_ON(vmf->flags & FAULT_FLAG_RETRY_NOWAIT);
#ifdef CONFIG_DEBUG_VMif (printk_ratelimit()) {printk(KERN_WARNING"FAULT_FLAG_ALLOW_RETRY missing %x\n",vmf->flags);dump_stack();}
#endifgoto out;}/** Handle nowait, not much to do other than tell it to retry* and wait.*/ret = VM_FAULT_RETRY;if (vmf->flags & FAULT_FLAG_RETRY_NOWAIT)goto out;/* take the reference before dropping the mmap_lock */userfaultfd_ctx_get(ctx);init_waitqueue_func_entry(&uwq.wq, userfaultfd_wake_function);uwq.wq.private = current;uwq.msg = userfault_msg(vmf->address, vmf->real_address, vmf->flags,reason, ctx->features);uwq.ctx = ctx;uwq.waken = false;blocking_state = userfaultfd_get_blocking_state(vmf->flags);/** Take the vma lock now, in order to safely call* userfaultfd_huge_must_wait() later. Since acquiring the* (sleepable) vma lock can modify the current task state, that* must be before explicitly calling set_current_state().*/if (is_vm_hugetlb_page(vma))hugetlb_vma_lock_read(vma);spin_lock_irq(&ctx->fault_pending_wqh.lock);/** After the __add_wait_queue the uwq is visible to userland* through poll/read().*/__add_wait_queue(&ctx->fault_pending_wqh, &uwq.wq);/** The smp_mb() after __set_current_state prevents the reads* following the spin_unlock to happen before the list_add in* __add_wait_queue.*/set_current_state(blocking_state);spin_unlock_irq(&ctx->fault_pending_wqh.lock);if (!is_vm_hugetlb_page(vma))must_wait = userfaultfd_must_wait(ctx, vmf, reason);elsemust_wait = userfaultfd_huge_must_wait(ctx, vmf, reason);if (is_vm_hugetlb_page(vma))hugetlb_vma_unlock_read(vma);release_fault_lock(vmf);if (likely(must_wait && !READ_ONCE(ctx->released))) {wake_up_poll(&ctx->fd_wqh, EPOLLIN);schedule();}__set_current_state(TASK_RUNNING);/** Here we race with the list_del; list_add in* userfaultfd_ctx_read(), however because we don't ever run* list_del_init() to refile across the two lists, the prev* and next pointers will never point to self. list_add also* would never let any of the two pointers to point to* self. So list_empty_careful won't risk to see both pointers* pointing to self at any time during the list refile. The* only case where list_del_init() is called is the full* removal in the wake function and there we don't re-list_add* and it's fine not to block on the spinlock. The uwq on this* kernel stack can be released after the list_del_init.*/if (!list_empty_careful(&uwq.wq.entry)) {spin_lock_irq(&ctx->fault_pending_wqh.lock);/** No need of list_del_init(), the uwq on the stack* will be freed shortly anyway.*/list_del(&uwq.wq.entry);spin_unlock_irq(&ctx->fault_pending_wqh.lock);}/** ctx may go away after this if the userfault pseudo fd is* already released.*/userfaultfd_ctx_put(ctx);out:return ret;
}

看起来像是不知道什么原因导致调度出去后,一直没有被唤醒
在这里插入图片描述
使用crash进一步验证猜想,随便找一个bt看下,确实是schedule调度出去之后没有再被唤醒。
在这里插入图片描述
先看一下uffd ctx里的这几个工作队列情况
在这里插入图片描述
需要找到ctx地址
vm_fault->vm_area_struct->vm_userfaultfd_ctx,vm_fault结构体是第一个参数传进来的,
在这里插入图片描述
handle_userfault这个函数的汇编比较复杂,往上找找,在上层函数把vmf变量定义在了栈里,
在这里插入图片描述
bt -f查看栈帧,hugetlb_handle_userfault帧里的前几个地址看起来像是给结构体赋值的参数,尝试解析一下
在这里插入图片描述
vm_ops解析出了<hugetlb_vm_ops>,看起来没啥问题,那解析下ctx
在这里插入图片描述
fault_pending_wqh队列的next!=prev,说明有pf请求没有被处理,所以D住了,其他队列的next=prev,都是空的。
在这里插入图片描述
在这里插入图片描述
waitq看一下pending队列,结构体的第一个元素,地址就是结构体的地址,可以看到这5个kworker就是对应的pf请求线程,由于没有被处理,导致D住了,那么接下来就要看一下pf请求为什么没有被处理。
在这里插入图片描述
同时也观察到,引用计数为6,但是5个kworker+firecracker+orchestrator应该是7才对,看一下firecracker和orchestrator的状态,由于是pf请求没有被处理,着重排查orchestrator
在这里插入图片描述
通过mm找到对应的firecracker进程
在这里插入图片描述
在这里插入图片描述
找到task_struct中的pid,就是对应的firecracker进程号
在这里插入图片描述
firecracker进程还在,引用计数那就是少了orchestrator的,可能是close了,也可能是orchestrator进程退了
在这里插入图片描述
ps一看发现orchestrator服务的启动时间居然在firecracker之后,
而且查看e2b代码发现,orchestrator服务close uffd之前会先kill掉firecracker进程,猜测可能是orchestrator重启了,而且没有走正常的关闭sandbox的流程,导致这些firecracker进程残留了,同时也没法再处理这些firecracker的pagefault请求,导致内核线程进入了D状态。

与运维确认是我们发布了新版本,orchestrator服务确实重启过了,问题确认清楚了,解决办法先完善发布流程,升级重启前先进行排水。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/81272.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入解析:构建高性能异步HTTP客户端的工程实践

一、架构设计原理与核心优势 HTTP/2多路复用技术的本质是通过单一的TCP连接并行处理多个请求/响应流&#xff0c;突破了HTTP/1.1的队头阻塞限制。在异步编程模型下&#xff0c;这种特性与事件循环机制完美结合&#xff0c;形成了高性能网络通信的黄金组合。相较于传统同步客户…

根据台账批量制作个人表

1. 前期材料准备 1&#xff09;要有 人员总的信息台账 2&#xff09;要有 个人明白卡模板 2. 开始操作 1&#xff09;打开 人员总的信息台账&#xff0c;选择所需要的数据模块&#xff1b; 2&#xff09;点击插入&#xff0c;选择数据透视表&#xff0c;按流程操作&…

《AI大模型应知应会100篇》第65篇:基于大模型的文档问答系统实现

第65篇&#xff1a;基于大模型的文档问答系统实现 &#x1f4da; 摘要&#xff1a;本文详解如何构建一个基于大语言模型&#xff08;LLM&#xff09;的文档问答系统&#xff0c;支持用户上传 PDF 或 Word 文档&#xff0c;并根据其内容进行智能问答。从文档解析、向量化、存储到…

RTK哪个品牌好?2025年RTK主流品牌深度解析

在测绘领域&#xff0c;RTK 技术的发展日新月异&#xff0c;选择一款性能卓越、稳定可靠的 RTK 设备至关重要。2025 年&#xff0c;市场上涌现出众多优秀品牌&#xff0c;本文将深入解析几大主流品牌的核心竞争力。 华测导航&#xff08;CHCNAV&#xff09;&#xff1a;技术创…

SpringCloud微服务开发与实战

本节内容带你认识什么是微服务的特点&#xff0c;微服务的拆分&#xff0c;会使用Nacos实现服务治理&#xff0c;会使用OpenFeign实现远程调用&#xff08;通过黑马商城来带你了解实际开发中微服务项目&#xff09; 前言&#xff1a;从谷歌搜索指数来看&#xff0c;国内从自201…

pgsql14自动创建表分区

最近有pgsql的分区表功能需求&#xff0c;没想到都2025年了&#xff0c;pgsql和mysql还是没有自身支持自动创建分区表的功能 现在pgsql数据库层面还是只能用老三样的办法来处理这个问题&#xff0c;每个方法各有优劣 1. 触发器 这是最传统的方法&#xff0c;通过创建一个触发…

math toolkit for real-time development读书笔记一三角函数快速计算(1)

一、基础知识 根据高中知识我们知道&#xff0c;很多函数都可以用泰勒级数展开。正余弦泰勒级数展开如下&#xff1a; 将其进一步抽象为公式可知&#xff1a; 正弦和余弦的泰勒级数具有高度结构化的模式&#xff0c;可拆解为以下核心特征&#xff1a; 1. 符号交替特性 正弦级…

uni-app 中适配 App 平台

文章目录 前言✅ 1. App 使用的 Runtime 架构&#xff1a;**WebView 原生容器&#xff08;plus runtime&#xff09;**&#x1f4cc; 技术栈核心&#xff1a; ✅ 2. WebView Native 的通信机制详解&#xff08;JSBridge&#xff09;&#x1f4e4; Web → Native 调用&#xf…

SpringBoot基础(静态资源导入)

静态资源导入 在WebMvcAutoConfiguration自动配置类中 有一个添加资源的方法&#xff1a; public void addResourceHandlers(ResourceHandlerRegistry registry) { //如果静态资源已经被自定义了&#xff0c;则直接生效if (!this.resourceProperties.isAddMappings()) {logg…

基于OpenCV的人脸识别:LBPH算法

文章目录 引言一、概述二、代码实现1. 代码整体结构2. 导入库解析3. 训练数据准备4. 标签系统5. 待识别图像加载6. LBPH识别器创建7. 模型训练8. 预测执行9. 结果输出 三、 LBPH算法原理解析四、关键点解析五、改进方向总结 引言 人脸识别是计算机视觉领域的一个重要应用&…

ElasticSearch重启之后shard未分配问题的解决

以下是Elasticsearch重启后分片未分配问题的完整解决方案&#xff0c;结合典型故障场景与最新实践&#xff1a; 一、快速诊断定位 ‌检查集群状态 GET /_cluster/health?pretty # status为red/yellow时需关注unassigned_shards字段值 ‌ 2.查看未分配分片详情 …

CSS- 3.1 盒子模型-块级元素、行内元素、行内块级元素和display属性

本系列可作为前端学习系列的笔记&#xff0c;代码的运行环境是在HBuilder中&#xff0c;小编会将代码复制下来&#xff0c;大家复制下来就可以练习了&#xff0c;方便大家学习。 HTML系列文章 已经收录在前端专栏&#xff0c;有需要的宝宝们可以点击前端专栏查看&#xff01; 点…

Git/GitLab日常使用的命令指南来了!

在 GitLab 中拉取并合并代码的常见流程是通过 Git 命令来完成的。以下是一个标准的 Git 工作流&#xff0c;适用于从远程仓库&#xff08;如 GitLab&#xff09;拉取代码、切换分支、合并更新等操作。 &#x1f310; 一、基础命令&#xff1a;拉取最新代码 # 拉取远程仓库的所…

HTML 表格与div深度解析区别及常见误区

一、HTML<div>元素详解 <div>是HTML中最基本的块级容器元素&#xff0c;本身没有语义&#xff0c;主要用于组织和布局页面内容。以下是其核心用法&#xff1a; 1. 基础结构与特性 <div><!-内部可包含任意HTML元素 --><h2>标题</h2><p…

mybatisPlus 新增时 其他字段的值和 id 保持一致实现方法

MyBatis-Plus 实现 sp_id_path 与 id 同步的方案 要实现新增时 sp_id_path 自动与 id 保持一致&#xff0c;需要在实体类和插入逻辑中做相应处理。MyBatis-Plus 提供了几种方式来实现这一需求&#xff1a; 方案一&#xff1a;使用 MyBatis-Plus 的自动填充功能 这是最优雅的…

兰亭妙微设计:为生命科技赋予人性化的交互语言

在医疗科技日新月异的今天&#xff0c;卓越的硬件性能唯有匹配恰如其分的交互语言&#xff0c;方能真正发挥价值。作为专注于医疗UI/UX设计的专业团队&#xff0c;兰亭妙微设计&#xff08;www.lanlanwork.com&#xff09;始终相信&#xff1a;每一处像素的排布&#xff0c;都应…

Tcping详细使用教程

Tcping详细使用教程 下载地址 https://download.elifulkerson.com/files/tcping/0.39/在windows环境下安装tcping 在以上的下载地中找到exe可执行文件&#xff0c;其中tcping.exe适用于32位Windows系统&#xff0c;tcping64.exe适用于64位Windows操作系统。 其实tcping是个…

springCloud/Alibaba常用中间件之Seata分布式事务

文章目录 SpringCloud Alibaba:依赖版本补充Seata处理分布式事务(AT模式)AT模式介绍核心组件介绍AT的工作流程&#xff1a;两阶段提交&#xff08;**2PC**&#xff09; Seata-AT模式使用Seata(2.0.0)下载、配置和启动Seata案例实战前置代码添加全局注解 GlobalTransactional Sp…

COMSOL随机参数化表面流体流动模拟

基于粗糙度表面的裂隙流研究对于理解地下水的流动、污染物传输以及与之相关的地质灾害&#xff08;如滑坡&#xff09;等方面具有重要意义。本研究通过蒙特卡洛方法生成随机表面形貌&#xff0c;并利用COMSOL Multiphysics对随机参数化表面的微尺度流体流动进行模拟。 参数化…

初识——QT

QT安装方法 一、项目创建流程 创建项目 入口&#xff1a;通过Qt Creator的欢迎页面或菜单栏&#xff08;文件→新建项目&#xff09;创建新项目。 项目类型&#xff1a;选择「Qt Widgets Application」。 路径要求&#xff1a;项目路径需为纯英文且不含特殊字符。 构建系统…