新闻详情

新闻详情

首页 / 资讯中心 / 详情

eMMC BKOPS机制深度解析:从MMC协议到闪存后台维护

发布时间:2026/9/8 5:19:57来源:尧图网络
eMMC BKOPS机制深度解析:从MMC协议到闪存后台维护
“MMC”这个词我第一次认真对待是在一次远程排查Android开发板卡顿的时候。设备连续写了几十GB日志界面开始间歇性掉帧dmesg里全是timeout重试SSH偏偏又能连上。同事丢过来一句“看看mmc bkops是不是在忙。”这一句话把我从文件系统层直接按到了存储芯片层。翻完eMMC 5.1规范才意识到这颗不起眼的黑色BGA芯片牵扯的是闪存介质、控制器固件、内核驱动三层协作的一整套逻辑。这也是为什么现在搜“MMC”相关热词几乎都会带着bkops一起出现——它就像eMMC的“加班时间表”平时看不见一出现就影响着设备性能。这篇就把这条线从头捋一遍从MMC的起源讲到eMMC内部原理再拆开bkops这个关键词最后落到工程实践里的避坑经验。1. 三个字母MMC在不同圈子里各指什么1.1 先把最容易混淆的三样东西分清楚MMC这个缩写在不同领域里各有归宿。Windows运维那边CLI里敲mmc打开的是微软管理控制台摄影圈老玩家口中的MMC是九十年代末的多媒体存储卡而在嵌入式、手机、平板、工控设备领域我们说的MMC几乎都指向eMMC——embedded MultiMediaCard嵌入式多媒体卡。如果你拆过一台老安卓手机的主板会看到存储部分是一颗焊死的黑色方形芯片丝印上可能有“eMMC”“Toshiba”“Samsung”之类的字样它就是eMMC。这里有个容易混的点MMC插卡、SD卡、eMMC三者是“血缘关系”但不是同一物种。MMC卡MultiMediaCard1997年由SanDisk和西门子推出的可拆卸存储卡外形比SD卡略厚今天的新设备基本见不到了。SD卡从MMC演进而来兼容MMC协议但增加了安全认证与版权保护机制外形更薄后来统治了相机和开发板市场。eMMC在MMC协议基础上为嵌入式场景重度改造直接焊在板上不可拆卸内部自带控制器整个存储系统被封装成一颗标准芯片。这三者的关系可以这样记eMMC是“焊死的SSD思维产物”SD卡是“能拔下来的MMC后代”。但它们在命令协议层面共享了大量设计基因。1.2 一条时间线从可拆卸卡到手机标配MMC的历史起点是1997年MMCAMultiMediaCard Association成立。之后MMC标准历经1.0、2.0、3.0几个版本数据线从1位扩展到8位速度从2.5MB/s爬升到几十MB/s。1999年前后SD卡从MMC分支出去SD卡在消费市场上反超了MMC但MMC协议本身没有死而是换了一条赛道活着。2004年前后MMCA并入JEDEC固态技术协会eMMC标准体系正式建立。此后JEDEC连续发布多个大版本eMMC 4.3引入Boot分区、RPMB重放保护内存块、可靠写等能力这阶段eMMC开始成为智能手机存储标配。eMMC 4.4 / 4.41完善系统唤醒、分区切换逻辑老设备上常见。eMMC 4.5加入缓存、Sanitize彻底擦除和本文重点的BKOPS机制。eMMC 5.0引入HS400模式理论带宽达到400MB/s同时支持增强类可配置分区。eMMC 5.1修正了一批生产制造和可靠性细节是目前最后也是使用最广的eMMC版本。后来UFSUniversal Flash Storage在中高端手机上逐步取代eMMC但eMMC没有因此消失——它凭借低成本和成熟生态在平板、电视盒子、车载、工业设备、网络设备里依然是海量存在。“厂商还在大批量采购eMMC”这件事本身就说明这个标准依然有很强的工程价值。1.3 为什么厂商愿意为“标准化的闪存管理”买单早年用裸NAND做产品是件痛苦的事。三星、海力士、闪迪、东芝各家的颗粒接口不同、坏块策略不同、ECC算法不同即使同一家厂商不同制程的颗粒行为也天差地别系统软件得为每颗颗粒单独适配开发周期和故障率都居高不下。eMMC的意义在于把NAND颗粒、控制器、FTL固件Firmware Translation Layer全部封装进一颗标准芯片对外暴露一套统一、稳定的MMC命令接口。主控端不再需要关心底层颗粒是SLC、MLC还是TLC也不需要知道坏块管理怎么实现更不用纠结磨损均衡算法是否有坑。系统只需要会发MMC命令、处理响应就能稳定使用任意供应商的eMMC芯片。这种“标准化封装”对产品研发来说省掉了大量底层适配工作对供应链来说则意味着可以灵活切换多家颗粒供应商而无需修改主板和驱动。用一句工程上的话总结eMMC把闪存管理的复杂度从系统软件转移到了芯片内部代价是性能和灵活性稍打折扣但换来的是极大的通用性。2. 拆开一枚eMMC芯片BGA封装里的三个角色2.1 引脚与物理接口CLK、CMD、DAT[7:0]和那些电源拿到一颗eMMC芯片最直观的是它的BGA封装常见球数在153、169、186等规格。引脚里最重要的几组是CLK时钟线主机提供决定传输速率。HS400模式下时钟频率可达200MHz。CMD双向命令/响应线主机发命令、设备回响应都走这一条线。这里注意CMD线只有一根所以命令交互是半双工的。DAT[7:0]8位双向数据线实际支持1/4/8位三种总线宽度。位数越高一次吞吐越大。RST_n硬件复位低电平有效。这个引脚能让eMMC在系统异常时快速回到初始状态省掉软件复位流程。VCC、VCCQ等电源引脚VCC供给主闪存核心VCCQ供给信号接口和控制器逻辑。不同速率模式对VCCQ的电压要求也不同HS400通常要求1.8V。值得一提是eMMC的数据线是可配置的。系统上电后默认工作在1位模式软件读取EXT_CSD了解设备能力后再通过SWITCH命令切换到4位或8位模式。如果驱动在初始化阶段没有正确配置总线宽度你会发现eMMC读写的吞吐低得可疑但并不会报错——这就是那种“查了半天参数最后发现总线在8位模式下没切过去”的问题。2.2 MMC协议的工作逻辑命令、响应与块传输MMC协议是典型的主从架构。主机是唯一的发起方设备只能被动响应。所有操作都由主机发送命令开始设备在完成命令后返回一个或多个响应字。说人话就是主机问一句设备答一句全程不允许设备主动开口。初始化流程大概是这样的CMD0GO_TO_IDLE把所有设备都拉到空闲态。CMD1SEND_OP_COND主机探测设备电压范围和工作条件直到设备返回“上电完成”。CMD2ALL_SEND_CID让设备上报自己的身份信息CID包括厂商ID、产品名、序列号等信息。CMD3SET_RELATIVE_ADDR给设备分配一个短地址RCA之后的操作都用这个地址寻址。CMD9/CMD7等读取CSD选定当前操作的设备。CMD6SWITCH读取或写EXT_CSD寄存器这是后续配置分区、总线宽度、DDR模式、bkops的关键命令。读写数据的流程则更直接主机发CMD17读单块或CMD18读多块再发CMD24写单块或CMD25写多块。多块写之前还可以用CMD23指定块数避免由于边界不确定导致跨块写被设备放大。这里要理解一个关键点MMC设备暴露给主机的地址空间是线性的、逻辑的。主机眼里这是一个又一个4KB的块但设备内部把这些逻辑块映射到物理页。这种“主机只管逻辑地址”的设计大大降低了上层软件复杂度代价是每次写放大、垃圾回收的实际情况主机并不能实时完全掌握。2.3 控制器和固件的三件大事映射、回收、磨损均衡eMMC内部负责存储管理的是一个微型“SSD主控”它内置了FTL固件负责把上层逻辑地址翻译成闪存物理地址。为什么要这套机制因为NAND闪存有两条物理铁律必须先擦除才能写入而且擦的最小单位是块Block一般大小为几MB。写的单位是页Page一般4KB或8KB但写入量小于一页时也会占掉整页多余空间称为“写放大”。因此如果主机要覆盖写某个逻辑页里的几个字节FTL不会真的去覆盖那块物理页而是把新数据写入一个空闲物理页再把逻辑到物理的映射表更新过去。原来那个物理页就变成了“无效页”等这一块里无效页攒多了控制器会触发垃圾回收把仍有效的页搬家到别的空闲块然后整块擦除。磨损均衡也在这里做文章。垃圾回收会让有些块被反复擦写有些块却几乎没动过。FTL要做的是让所有物理块的擦写次数尽量接近否则个别块提前到寿命上限整个设备的可用容量就会缩水。动态磨损均衡处理频繁更新的热数据块静态磨损均衡则会把长期不动的静态数据搬去磨损较少的块让那些低频块也参与消耗。这三件事全部由控制器在芯片内部悄悄完成不占用主机CPU。这也是为什么eMMC“只是个存储芯片”但对系统体验的影响却可以很大——控制器内部一旦忙碌外面的命令就会排队等待表现在应用层就是I/O延迟波动。3. bkops这条热搜词背后闪存为什么要“偷偷加班”3.1 闪存不自律数据保持、读干扰和擦写不对称如果你只看FTL的日常似乎只要GC和磨损均衡做好就够了。但闪存还有一些更阴间的物理特性需要在“没事做”的时候定期维护这类维护操作就是Background Operations简称BKOPS。第一个问题叫数据保持。NAND闪存里的电荷会随时间慢慢泄漏尤其是TLC和QLC颗粒电荷窗口小泄漏风险高。一颗eMMC设备可能出厂后放在仓库里半年再上电读取时发现某页的比特翻转已经超出ECC纠错能力。设备内部的读刷新Read Refresh机制要把那些快要失效的物理页读出来重新编程一遍防止静默数据损坏。第二个问题叫读干扰。频繁读同一个块会让相邻块里的浮栅电荷受到影响久而久之也会出现位错误。控制器需要定期扫描那些读密集的区域把内容搬到新位置并擦掉被“读乱”的原始块。第三个问题是磨损均衡的滞后性。FTL的静态磨损均衡不会每次写入都立即执行因为频繁搬动静态数据反而会造成额外写放大。控制器会等到系统有一定空闲资源时分批次地调整那些磨损不均的块。这些维护操作必须在设备上电后、主机发命令的间隙完成因为eMMC不知道下一秒会不会掉电。如果它永远等不到“空闲”就会在主机的下一次读写时强行插队表现出来就是突发延迟。3.2 Manual BKOPS与Auto BKOPS两种触发方式的门道eMMC 4.5开始JEDEC正式把BKOPS机制写进规范。大体分为Manual BKOPS和Auto BKOPS两种。Manual BKOPS手动后台操作逻辑如下主机在合适的时候执行SWITCH命令去读EXT_CSD里的BKOPS_STATUS字段。该字段会给出一个状态常见状态包括无需操作No BKOPS、需要操作BKOPS Needed、紧急操作BKOPS Urgent。如果状态显示需要或紧急主机通过SWITCH写入BKOPS_START告诉设备“你可以执行后台维护了”。设备开始内部维护期间主机依然可以发其他命令但性能必然受影响。设备维护完成后再把BKOPS_STATUS清回No BKOPS状态。Auto BKOPS则更进一步。如果主机在EXT_CSD的BKOPS_EN字段里写入使能值设备就可以在内部自己判断时机在命令间隙自动启动后台维护不必每次都等主机来“催”。问题恰恰出在这里Auto BKOPS会让设备更积极地做维护但也更不可控。你没法精确知道它什么时候在“偷偷加班”某次大数据量写入撞上它内部GCI/O延迟就可能突然抬升。Manual BKOPS虽然可预期却要求驱动和系统设计者配合好在空闲窗口主动触发如果一直不触发设备只能被迫在工作时刻占用带宽体验更差。内核里对这两种模式的取舍标准概括起来就是Devices with poor random write performance often benefit from enabling BKOPS。这句话翻译成人话就是颗粒越差越需要系统主动帮它安排“加班时间”。3.3 一个真实卡顿案例持续写入后性能为什么会崩我在调试那台开发板时复现性能问题的方式很简单用dd做几百兆的持续写入同时监控iostat。正常前几秒写吞吐能到几十MB/s。持续写入几十秒后吞吐会掉到个位数并且伴随明显的RTO波动。iostat里w_await从十几毫秒飙到几百毫秒甚至上秒。这时候查dmesg能看到mmc0: Timeout waiting for hardware interrupt这就是典型的设备内部正在做维护而主机等不到响应。继续用mmc-utils的extcsd读取可以看到BKOPS_STATUS已经处于非No BKOPS状态说明设备觉得自己“有事要做”但主机没有及时给它维护窗口。这个案例复盘时问题不是设备坏了而是系统里IO调度策略太激进。我们把所有线程都压着写没有给eMMC留下任何空闲间隙设备找不到机会执行内部GC只能在下一次命令时强行“插队”把性能波动放大给了每一个上层应用。3.4 实操观测在Linux下查看bkops状态与寿命信息想验证eMMC有没有在忙后台操作Linux下最直接的路径是sysfs和mmc-utils。查看设备基本信息和寿命估算cat /sys/block/mmcblk0/device/life_time cat /sys/block/mmcblk0/device/pre_eol_infolife_time文件的格式通常是两个十六进制数分别对应类型A和类型B的寿命估算。值越小越好例如0x01通常表示寿命消耗在10%以内。pre_eol_info正常值是0x1对应“Normal”如果出现0x2Warning甚至0x3Urgent说明保留块耗尽程度已经到了警告线。用mmc-utils看EXT_CSDmmc extcsd read /dev/mmcblk0在输出里重点找这些字段BKOPS_EN0x01表示Auto BKOPS已使能。BKOPS_STATUS0x00表示当前无需后台操作非0则表示有维护需求。PRE_EOL_INFO生命周期预警信息。DEVICE_LIFE_TIME_EST_TYP_A / TYPE_B类型A/B的寿命估算。生产环境下建议把这些信息接入告警平台定期记录寿命消耗曲线。如果一台设备life_time在很短时间从0x01跳到0x06不要犹豫优先查散热、掉电次数和写入压力大概率是环境或配置出了问题。4. 从手机到工业设备eMMC的真实应用图景4.1 手机上的eMMC存量巨大、体验宽窄不一手机是eMMC最经典的战场。安卓早期到中期的存储几乎全靠eMMC从eMMC 4.3到5.1每一代升级都在解决体验问题。后来UFS凭借全双工、命令队列等特性把顺序读速度拉到了千兆级别成为旗舰机首选。但定位入门机和低端平板的设备到今天仍在大量使用eMMC。eMMC在手机里的运行方式简单直观Boot1分区存放引导加载器Boot2分区常用来放恢复系统RPMB分区存密钥、防回滚计数器等安全数据用户数据区则被分区成system、vendor、data等。启动过程中ROM先读Boot1拉起bootloaderbootloader再通过MMC命令读取用户分区的system镜像逐步加载内核和文件系统。由于eMMC内部没有命令队列同一时刻只能有一个命令在跑所以多线程随机读写很容易排队。这就是为什么低端机玩一会儿微信就觉得卡——大量小文件随机写挤在一条命令队列里吞吐自然上不去。UFS引入命令队列后这个瓶颈被解除了但成本也上去了。4.2 工业与车载场景对寿命、温度和确定性的苛刻要求消费级eMMC已经很成熟但工业和车载场景对存储的要求要严苛得多。温度是第一个分水岭。普通消费级eMMC工作温度通常在-25°C到85°C工业级可以做到-40°C到85°C有些车规级产品甚至要求-40°C到105°C。温度对NAND电荷保持的影响是指数级的高温加速泄漏低温又影响写入稳定。选型时一定要看颗粒供应商明确标注的温度等级别拿消费级片子冒充工业级用。寿命是第二个问题。车载设备往往要服役7到10年行车记录仪一类设备会持续写入视频流。选TLC还是MLC、留多少OPOver-Provisioning空间、控制器固件的磨损均衡策略是否激进这些直接决定几年后设备是否突然“变砖”。经验上长时间连续写入的场景尽量选寿命余量更大的颗粒类型或更高等级eMMC并配合温度管理措施散热片不是可选项。RPMB在工业和车载里也扮演重要角色。安全启动的密钥、设备唯一ID、防止固件回滚的计数器都存放在RPMB里利用HMAC-SHA256做访问认证能有效防止冷数据被恶意重放。如果新板卡连RPMB的基础读写都调不通基本是密钥管理流程和驱动配合没做好。4.3 选型决策eMMC、UFS、SD卡还是裸NAND选存储方案不要只迷信参数表先看你的系统软件栈、成本约束和生命周期再决定接口。维度eMMCUFSSD卡裸NAND接口8位并行半双工M-PHY串行全双工SD协议/SPI自定义最高理论速度400MB/sHS400830MB/s起几十到200MB/s取决于主机实现命令队列无有无无软件复杂度低中低高坏块/磨损管理芯片内部处理芯片内部处理设备端主机必须自己做使用场景手机/平板/工业/车载旗舰手机/笔记本/高性能嵌入式相机/树莓派/消费电子定制SSD/极简系统裸NAND看着便宜但把FTL、坏块管理、ECC全交给主机端开发周期和风险会显著拉高不适合大多数产品团队。SD卡接口简单但可靠性、温度范围和固定安装方式都不如焊接式方案。UFS性能最好但成本高而且启动流程、固件适配相对复杂。对绝大多数中低端嵌入式产品来说eMMC仍然是性价比和可靠性最平衡的选项。5. 工程落地避坑记录对齐、掉电与寿命监控5.1 分区对齐一个小设置影响整盘GC效率eMMC内部光看逻辑块地址好像很规律但物理页、物理块之间有固定对齐关系。如果系统给eMMC分区时起始扇区不是整数倍块边界对齐比如一个4KB块被分成两个分区跨边界的写入就会被FTL拆成多次内部操作垃圾回收复杂度上升写放大系数跟着恶化。排查方法很简单parted /dev/mmcblk0 align-check optimal 1如果显示不理想重新分区时让起始扇区为8192的整数倍对应4MB对齐这是一个兼顾性能和兼容性的常用做法。很多量产脚本里用fdisk时默认起始扇区是2048在eMMC上虽然也能用但并不是所有颗粒的最优选择。别嫌这步麻烦分区对齐不对齐在长期运行后的寿命和性能差异是能测出来的。5.2 掉电保护别以为eMMC能扛住一切eMMC控制器有缓存和内部映射表掉电瞬间正在写入的数据不一定落盘。虽然大多数eMMC有掉电恢复机制能保证已经返回“写成功”的数据不丢但如果系统没有正确使用刷新命令数据可靠性还是打折扣。Linux下常见的坑是文件系统虽然挂在ext4上但没明确开启barrier或者上层应用不关心fsync。压力测试时大文件写入看着完成了实际上数据还躺在内存页缓存里一断电就丢。更隐蔽的是控制器内部的写缓存需要发送FLUSH_CACHE命令才能真正落盘。做掉电测试时我的做法是准备一套循环脚本交替写入随机数据和校验数据。每次写完固定大小数据后调用fsync并记录数据位置。随机时间点切断电源。重新上电后挂载文件系统并校验已记录的数据内容。反复跑几十轮才能对板子的掉电可靠性有底。只做一次冷启动验证根本不叫测试。5.3 用sysfs和mmc-utils做寿命监控eMMC的寿命不会突然归零它有明确的“提前量”。定期读取下面这些信息能帮你预判设备剩余寿命。mmc extcsd read /dev/mmcblk0 | grep -E PRE_EOL|LIFE_TIME|BKOPS把每次读取的结果记录下来配合时间戳形成趋势图。如果看到pre_eol_info从Normal变成Warning就要开始规划设备轮换或减少写入了。如果BKOPS_EN一直处于未使能状态而设备又频繁出现性能抖动可以尝试在系统启动早期启用Auto BKOPS再观察延迟曲线。有些设备的寿命信息只能在“可编程区域”里读少量厂商还会故意隐藏部分字段。遇到这种情况先确认你使用的mmc-utils版本和内核版本是否较新再查厂商手册是否有专有命令。5.4 三个真实踩坑记录坑一某批次设备使用半年后寿命估算数据异常偏高。排查链路是先看dmesg有无异常ECC错误再看life_time并配合写入量估算最后发现是量产阶段的持续写入压力测试次数过多导致颗粒磨损集中。解决方法是调整产测流程将全盘写测试从每台多次改为抽检并加软件升级阶段白名单避免每台机器都重复整盘刷写。坑二开发板在做持续数小时的日志写入测试时出现周期性卡顿。我一度以为是文件系统问题后来抓取iostat发现w_await周期性飙升再读BKOPS_STATUS确认是有后台操作发生。解决方式是调整测试脚本每写一段数据后主动追加sleep间隙同时在内核配置里打开Auto BKOPS让设备提前利用这些间隙做维护卡顿现象明显缓解。坑三某工控设备在高温老化工序后上报的启动时间变长。排查发现是高温箱内温度达到85°C以上NAND读干扰和电荷泄漏加重FTL频繁做读刷新和重试。解决方案是把老化温度上限调低到70°C并在老化后的开机流程里增加文件系统自检同时加入温度降额控制逻辑高温环境下主动限制写入频率。这三个坑有一个共同点都不是eMMC芯片“坏了”而是系统没有充分理解存储介质的工作方式。对齐、掉电、温度、维护窗口这些词看起来是参数手册里的小字实际却是决定产品长期可靠性的关键。回到开头那个问题“mmc bkops”为什么会被反复搜索因为它代表了eMMC性能世界里最不可预测的那部分。对普通开发者来说建议不要只停留在“性能变差就换芯片”的层面先学会看BKOPS_STATUS、寿命字段和写放大数据很多时候优化一个后台操作的窗口比整体更换存储方案更有效。我现在做新板卡选型时都会把BKOPS机制是否可调、寿命监控是否有标准接口放进评估表。存储这行没有玄学所有看似突然的故障翻开手册都能找到源头。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

射频识别技术重构仓库管理系统:从选型到落地指南 2026/9/8 6:05:03

射频识别技术重构仓库管理系统:从选型到落地指南

简介:一套RFID仓库管理系统完整项目,面向需要开发或学习仓储信息化应用的开发者,覆盖到货检验、入库、分配库位、库存变动、查询与出库等环节的数据自动采集,帮助企业提高库存数据录入速度与准确性。包体共42个文件,压…

阅读更多 →
开源物联网云平台私有化部署选型与落地实践 2026/9/8 6:05:03

开源物联网云平台私有化部署选型与落地实践

先交代一下背景:这几年物联网项目从“能用就行”逐渐变成了“稳定、可控、可扩展”,很多团队在选平台时会卡在一个问题上——数据放公有云不放心、按设备数买商业授权又太贵,于是“私有化部署 开源”成了最现实的折中路线。我自己帮客户落地…

阅读更多 →
从Nanobot源码读懂OpenClaw架构:Agent循环与技能机制解析 2026/9/8 6:05:03

从Nanobot源码读懂OpenClaw架构:Agent循环与技能机制解析

1. 先搞清楚这件事的来龙去脉最近在折腾 OpenClaw,这个项目在 GitHub 上的热度一直不低,官方定位是“你的个人 AI 助理框架”,玩法相当野——既能接 Telegram、Discord 这些消息渠道,又能操作本地文件、执行命令,还能自…

阅读更多 →
可软件训练的电子鼻:传感器阵列与AI模型实现气味识别 2026/9/8 6:05:03

可软件训练的电子鼻:传感器阵列与AI模型实现气味识别

1. 项目概述与整体设计思路 1.1 可软件训练的电子鼻到底解决了什么问题 先聊一个很多人问过我的问题:电子鼻这玩意儿,和普通的单个气体传感器到底有啥本质区别? 单个气体传感器,比如我们常见的MQ-2、SGP40,核心能力是…

阅读更多 →
导航突然画出直线或禁行路线?从路网数据与定位原理说起 2026/9/8 6:05:03

导航突然画出直线或禁行路线?从路网数据与定位原理说起

早上我准备从住处骑到城郊的湿地公园,同一台手机、同一条起终点,我把百度地图和高德地图分别切到骑行模式,各规划了一次路线。结果很有意思:百度地图给的路线几乎是一条笔直的直线,看起来特别省事,可拉大一…

阅读更多 →
BMC固件工程师实战指南:从IPMI到Redfish的带外管理技术解析 2026/9/8 6:02:03

BMC固件工程师实战指南:从IPMI到Redfish的带外管理技术解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞