
上周一个做嵌入式的朋友把一块从工控机上拆下来的固态盘插到 MacBook 上磁盘工具里能看见一个灰色的分区点装载直接弹窗说无法装载、文件系统不被支持。盘里是几个月的交叉编译产物和一整套历史日志机器已经报废只剩这块盘。这种场面我遇到过不止一次从 Linux 服务器上拆下来的数据盘、树莓派上写满的 TF 卡、从机房拖回来的旧硬盘插到 macOS 上基本都是一个结果——能看见设备节点读不了内容。MACOS与EXT4这两个词凑在一起本质上是一个跨文件系统的兼容问题。macOS 原生能处理的文件系统是 APFS、HFS、exFAT、FAT32外加 UDF 和只读的 NTFSEXT4不在名单里。网上流传的装个软件就能读写 ext4的说法大部分要么停留在只读、要么早就没人维护、要么需要把系统安全性降下来才能跑。真正稳妥的做法其实只有几条路而且每条路的边界都很清楚。下面按我这些年的实际操作顺序把原理、方案选型、完整步骤、踩坑点全部拆开讲一遍不管你是只想把文件拷出来的小白还是需要长期在 macOS 上处理 Linux 磁盘的开发者都能找到对得上号的那一段。1. macOS 读不了 EXT4 到底卡在哪一层1.1 文件系统驱动必须进内核而 macOS 把这道门收紧了理解这个问题得先知道 macOS 的文件系统栈长什么样。内核里有一个 VFS 层往上给应用提供统一的 open/read/write/stat 接口往下对接具体的文件系统实现。APFS、HFS、exFAT 这些实现都是苹果自己写在内核里的系统启动时就注册好了。外部想加一个新的文件系统只有两条路写一个内核扩展KEXT挂进 VFS或者走 FUSE 这种用户态桥接框架。走 KEXT 这条路在今天的 macOS 上非常难。从 macOS 10.15 开始第三方内核扩展必须由用户在隐私与安全性里手动放行到了 Apple Silicon 机型还得重启进恢复模式在启动安全性实用工具里把安全策略从完整安全性降到降低安全性并勾选允许用户管理内核扩展。这个操作意味着放弃一部分系统完整性保护能力对生产机器来说是要慎重考虑的事。苹果自己当然有能力做一个 ext4 驱动但它没有任何商业动机——APFS 才是它要推的东西。所以现实就是官方版本永远不会支持第三方方案全部得绕路。这也解释了一个现象为什么很多教程让你装完重启再重启因为 macFUSE 这类框架的核心部分就是那个需要授权和降低安全策略的内核扩展装完没经过这套流程ext4fuse之类的工具连设备都打不开报错一般是fuse: device not found或者Library not loaded。1.2 EXT4 这套元数据设计决定了第三方只读实现的极限EXT4不是 FAT32 那种结构简单的东西它继承了 ext2/ext3 的整套设计并做了大量扩展。磁盘被划分成块组每个块组有超级块备份、组描述符、位图、inode 表目录使用 B 树htree做索引文件数据用 extent 树来记录连续块区间而不是传统的块指针数组。现代 ext4 默认还会打开 64bit、metadata_csum、flex_bg、dir_index 等特性位inode 大小默认 256 字节块大小 4096 字节。这套结构的读写逻辑非常复杂尤其是日志journal和延迟分配delayed allocation机制。写一个完整可靠的 ext4 读写在用户态实现基本不现实因为任何一处元数据更新出错整个盘就可能不可恢复。所以第三方的用户态实现清一色选择只读只解析已有的元数据树绝不落笔。这不是能力问题是风险控制问题——ext4fuse依赖 e2fsprogs 的libext2fs而libext2fs的写支持至今也只在 fsck 这类离线修复工具里被谨慎使用。再补一个概念VFS 层收到 write 之后并不会立刻落盘而是先进页缓存由内核的 writeback 线程按 dirty 时间刷出去sync是强制把脏页推下去umount则会走完整的回写与卸载流程。这套流程对 ext4 的日志回放有强依赖。你在 macOS 上绕过内核直接动 ext4 的盘等于跳过了这套一致性保障跨系统乱写的后果往往不是文件损坏这么简单而是整个文件系统结构崩掉。所以下面所有方案里凡涉及写的我一律坚持交给真正的 Linux 去处理。2. 四条落地路线怎么选先看你是读还是要写2.1 四种方案的适用边界对比我把这些年用过的方案整理成一张表先看这张表能省掉你大半的摸索时间。核心判断标准只有两个你是只读还是要写这块盘是一次性的还是长期要用的。方案读写能力是否需降低启动安全性依赖虚拟机典型耗时适合场景debugfs 直接提取文件只读不需要不需要5 分钟只要几个文件、系统不想改macFUSE ext4fuse只读需要Apple Silicon不需要30 分钟想浏览整盘目录结构dd 镜像 Linux 虚拟机挂载完整读写不需要需要40 分钟起盘有故障、需要 fsck、数据宝贵USB 设备直通 Linux 虚拟机完整读写不需要需要30 分钟长期使用、追求速度如果这块盘里的数据只值看一眼选第一行成本最低不碰系统任何设置。如果盘有异响、SMART 报警或者之前是异常断电的强烈建议选第三行先做完整镜像再操作原盘全程只读这样即使后面手抖了原始数据还在。如果这块盘你以后每周都要插那第二行和第四行可以组合起来用——只读浏览用 ext4fuse需要改文件的时候开虚拟机。2.2 为什么不推荐格式化一下再用这类方案网上还有一种说法把 ext4 分区格成 exFATmacOS 和 Linux 就都能读写了一劳永逸。这个建议在特定场景下成立但有几个代价必须提前说清楚。exFAT 不支持 Unix 权限位和所有者chmod、chown在它上面完全不起作用不支持符号链接和硬链接很多 Linux 项目目录树里的软链接会在拷贝过程中变成普通文件或者直接失败不支持设备文件也不支持稀疏文件的高效存储。对源码仓库、容器镜像、数据库目录、包含特殊字符和中文文件名的日志归档来说格成 exFAT 之后再拷回去很多东西会静默出错——最典型的就是 Git 仓库里的符号链接全部失效npm install之后node_modules/.bin里的一堆链接变成文本文件跑起来各种ENOENT。所以我的做法是跨系统交换的数据用 exFAT需要保持 Linux 语义的数据老老实实留在 ext4 上通过前面那张表里的方案去访问。这条线不要越。2.3 一个被严重低估的工具e2fsprogs 里的 debugfs很多 macOS 用户不知道Homebrew 里能装一个叫e2fsprogs的包它自带一个debugfs工具可以纯用户态、只读方式解析 ext4直接把文件导出到本地。它完全不需要 FUSE不需要内核扩展不需要降低系统安全性权限风险几乎为零。缺点是命令行操作没有图形界面而且只能一个一个文件或者整目录 dump。我处理紧急情况时一般先开这个工具看一眼盘到底还在不在能列出根目录说明超级块和 inode 表是好的后面无论走哪条路都稳如果连根目录都列不出来那基本可以判断盘有物理或者结构性损坏这时候第一件事应该是做镜像而不是继续折腾挂载。这个先探再治的顺序我建议你养成习惯比上来就猛装驱动强得多。3. 实操一macFUSE ext4fuse 只读拿到完整目录树3.1 安装 macFUSE 与 ext4fuse 的完整流程这一节的前提是你接受在系统里放一个第三方内核扩展。如果你用的是 Intel 机型而且系统还是 10.15 之前的版本流程会简单一些Apple Silicon 或者新系统必须多走几步。先装 macFUSE# 先确认 Homebrew 正常 brew --version # 安装 macFUSEcask 形式会走图形安装器 brew install --cask macfuse安装过程中会弹出系统扩展授权提示按提示到系统设置 → 隐私与安全性里找到被拦截的开发者扩展点击允许然后重启。Apple Silicon 机型还需要额外一步关机后长按电源键进入启动选项选择选项进入恢复模式从菜单里打开启动安全性实用工具选中你的系统盘点安全性策略改成降低安全性并勾选允许用户管理内核扩展保存后重启。这一步只做一次之后升级系统大版本可能需要重做。重启完成后装 ext4fusebrew install ext4fuse有个细节要注意Homebrew 里的ext4fuse版本偏老如果你的盘打开了 64bit 或者较新的 metadata_csum 特性标准版本可能报Filesystem has unsupported feature。遇到这种情况先试brew install ext4fuse --HEAD拉最新源码编译或者在 Linux 侧把盘上的新特性关掉再复制——不过关特性这个操作有风险不是万不得已不要做。实测下来绝大多数用 Ubuntu 22.04、Debian 12 默认参数格式化的盘标准版本就能正常读。3.2 找到设备节点并完成挂载第一步永远是先确认设备节点别急着挂diskutil list输出里你会看到类似external physical下面是/dev/disk4分区/dev/disk4s2类型标着Linux Filesystem或者干脆什么都没有。注意区分 disk 和 rdisk/dev/rdisk4是字符设备走它做镜像会快很多但挂载时要用/dev/disk4s2这种块设备节点。另外如果 macOS 弹窗问你要不要初始化这块盘一定点忽略千万别点初始化那等于直接抹盘。创建挂载点并挂载mkdir -p ~/mnt/ext4 ext4fuse /dev/disk4s2 ~/mnt/ext4 -o allow_other如果报Operation not permitted一般是两个原因一是 macFUSE 的扩展没被允许去系统设置里再看一眼二是allow_other被 macFUSE 默认关掉了需要在 macFUSE 的设置面板里勾上允许其他用户访问。挂载成功后ls ~/mnt/ext4就能看到根目录。卸载用diskutil unmount force ~/mnt/ext4注意这里一定要用diskutil unmount而不是直接umountFUSE 挂载点在 macOS 上走 Disk Arbitration 管理直接 umount 有时会留下僵尸挂载点后面再挂就报Resource busy只能重启清掉。3.3 只读场景下的实际表现与限制ext4fuse 能做什么、不能做什么我实测总结如下。目录遍历、文件读取、中文和特殊字符文件名、大于 4GB 的单个文件这些都没问题中文不乱码。速度上顺序读大文件大约在 40 到 80 MB/s 之间明显慢于原生挂载因为每个读请求都要从内核态切到用户态进程再切回来单线程处理CPU 占用也会上去。不能做的有三类。第一任何写操作包括创建、删除、修改属性全部报Read-only file system这是设计如此不要试图绕过。第二某些特殊文件如果你在 Linux 侧用过稀疏文件比如虚拟机镜像、truncate出来的文件ext4fuse 读出来可能是完整尺寸一个声明 100GB 稀疏镜像拷出来就真的是 100GB把目标盘撑爆这一点在拷贝虚拟机磁盘文件时要格外小心。第三非正常断电过的盘直接挂载可能读到不一致的数据某些文件看着有大小但内容是空的或者乱码这时候正确做法不是重试而是回到 Linux 里先跑e2fsck修完再读。另外提醒一句ext4fuse 这个项目本身已经很久没有活跃维护了能用是能用但别指望它跟进新的 ext4 特性。把它当作一个快速浏览工具需要认真处理数据的时候还是走下一节的虚拟机方案。4. 实操二虚拟机直通物理磁盘拿到完整读写能力4.1 直通物理盘还是直通 USB 设备这是整篇文章里最需要做决策的地方。虚拟机访问外接 ext4 盘有两种方式一是 USB 设备直通把整个 USB 存储设备从 macOS 手里抢过去交给虚拟机Linux 里看到的就是一块普通的 USB 硬盘二是块设备直通虚拟机直接以/dev/disk4为裸设备打开Linux 里看到的是一块 virtio 或者 SCSI 磁盘。我强烈推荐前者。原因在于 macOS 的 Disk Arbitration 服务会持续持有物理磁盘的访问权裸设备直通时宿主和客户机容易抢盘表现是随机 I/O 卡死、数据写入后读不到、甚至把分区表写花。而且裸设备直通通常需要sudo启动虚拟机权限管理也麻烦。USB 直通虽然牺牲一点便利性每次插拔要在虚拟机设置里重新勾选设备但边界清晰宿主 macOS 根本不会去碰这块盘安全性高一个数量级。虚拟化软件的选择上UTM 是最省事的免费开源基于 QEMU图形界面里直接有USB 设备面板插上盘刷新一下就能勾选。Parallels 和 VMware Fusion 也支持 USB 直通但个人版授权和版本差异要自己确认。如果习惯命令行直接用 QEMU 也行参数后面给。4.2 UTM 图形界面直通与 QEMU 命令行直通的写法用 UTM 的话先建一台 Ubuntu 或者 Debian 虚拟机官方镜像直接导入即可十几分钟装完关机后在虚拟机设置里找到 USB 相关选项插上硬盘点刷新列表里会出现类似JMicron Generic USB Disk的设备勾选它启动虚拟机。进系统后lsblk应该能看到sdb和sdb1。用命令行 QEMU 的思路是一样的先把设备从 macOS 卸载不是弹出是卸载卷sudo diskutil unmountDisk /dev/disk4然后启动 QEMU 时加上 USB 直通参数qemu-system-aarch64 \ -machine virt,accelhvf \ -cpu host -smp 4 -m 4096 \ -drive fileubuntu.qcow2,ifvirtio \ -device qemu-xhci \ -device usb-host,vendorid0x152d,productid0x0562 \ -nographicvendorid和productid可以用system_profiler SPUSBDataType查到。用usb-host的好处是它按 VID/PID 绑定不依赖具体的 bus 和 addr重插也能对上。如果报libusb权限问题检查是不是有别的进程占着设备通常就是 macOS 自己还没卸载干净。如果你的盘已经有明显的健康问题我更推荐第三条路——先做镜像彻底跟物理设备解耦# 确认分区大小预留足够空间 diskutil list /dev/disk4 # 用 rdisk 走字符设备速度快很多 sudo dd if/dev/rdisk4s2 of$HOME/ext4-backup.img bs8m convsparse statusprogressconvsparse这个参数很关键它让 dd 把全零块写成稀疏空洞一个实际用了 20GB 的 500GB 分区镜像文件可能只有 20 多 GB省下大量磁盘空间。做完镜像后把ext4-backup.img作为普通磁盘文件挂进虚拟机就行原盘可以安全收起来了。4.3 在 Linux 客户机里挂载、修盘与权限映射进到 Linux 客户机之后第一步是确认设备lsblk -f sudo blkidblkid会告诉你分区的 TYPE 是不是ext4、UUID 是什么、有没有metadata_csum之类的标志。如果盘之前是异常拔出的mount会拒绝提示cant read superblock或者filesystem needs recovery这时候别急着加-o ro先做一次强制检查sudo e2fsck -fy /dev/sdb1-f是强制检查即使文件系统标记为 clean-y是自动回答 yes。这一步会回放日志、清理孤儿 inode、修复不一致的位图。修完再挂sudo mkdir -p /mnt/ext4 sudo mount -t ext4 /dev/sdb1 /mnt/ext4权限映射是个容易踩的点。Linux 里 ext4 上文件的 uid/gid 是数字比如 1000:1000一般对应客户机里的第一个普通用户但校核一下id ls -ln /mnt/ext4/home如果 uid 对不上ls -l会显示成一串数字而不是用户名这不是盘的问题是客户机里没有对应的用户。真要精细控制可以在挂载时指定sudo mount -t ext4 -o uid1000,gid1000,umask022 /dev/sdb1 /mnt/ext4不过说实话只在虚拟机内部操作、最后通过共享目录往外拷的场景没必要纠结这个拷出去之后在 macOS 侧改一下属主就行因为我下面要讲的共享机制本身就会丢掉权限位。4.4 把数据传回 macOS 的两条可靠通道数据在 Linux 客户机里能读能写之后怎么回到 macOS 才是真正收尾的部分。两条通道我都常用按场景挑。第一条是共享目录。UTM 支持目录共享在虚拟机设置里指定一个 macOS 上的目录比如~/ext4-shareLinux 里挂载sudo mkdir -p /mnt/share sudo mount -t virtiofs share /mnt/share # 老一点的配置用 9p # sudo mount -t 9p -o transvirtio,version9p2000.L share /mnt/share然后rsync往外搬rsync -a --infoprogress2 /mnt/ext4/projects/ /mnt/share/projects/--infoprogress2会显示总进度和总速率比默认输出好用得多。注意共享目录会丢失 Unix 权限位和符号链接语义如果你搬的是代码仓库最好在 macOS 侧重新git clone一次再用 rsync 同步工作区而不是直接搬仓库目录。第二条是网络通道。UTM 默认会把客户机的 22 端口转发到宿主的 127.0.0.1:2222端口号可以在设置里改Linux 里开了 SSH 之后macOS 直接scp -P 2222 -r user127.0.0.1:/mnt/ext4/logs ./logs这条路的优点是保留更多元数据scp -p能带时间戳缺点是需要处理用户名密码或者密钥。如果只是搬几个大文件也可以在大文件所在目录起个临时 HTTP 服务python3 -m http.server 8000然后在 macOS 浏览器里点下载反而最省事。三条路我都用过日常首选 rsync遇到奇怪的文件名和权限问题时切 scp。5. EXT4 关键特性与兼容性坑位5.1 哪些特性组合最容易在 macOS 侧翻车下面这张表是我在实际处理中遇到的报错和对应原因的对照遇到问题直接查。报错或现象可能原因处理方式Filesystem has unsupported feature(s)盘启用了 64bit 或 metadata_csum工具版本旧改用--HEAD编译或走虚拟机方案cant read superblock日志未回放或超级块损坏Linux 里e2fsck -fy必要时用备份超级块Resource busy挂载点未正常卸载用diskutil unmount force还不行重启文件大小正常但内容为空非正常断电导致元数据不一致先 fsck不要反复挂载中文文件名乱码客户端 locale 或工具编码问题确认LANGext4fuse 一般正常拷贝后磁盘写满稀疏文件被展开成完整大小用 rsync 或tar打包后再传重点说两个。第一64bit 特性。现代 mkfs.ext4 在大于 16TB 的盘上默认开启普通盘也可以手动开。开了之后块号用 64 位表示老的解析工具直接罢工。第二metadata_csum。这是元数据校验和从 e2fsprogs 1.43 起成为默认好处是能发现静默损坏坏处是旧工具读不了。我个人的经验是不需要为了迁就 macOS 去关掉这两个特性正确做法是把解析工作交给 Linux让 ext4 保持默认配置这才是长期可持续的方案。还有一个容易忽略的点是 inode 大小。默认 256 字节的 inode 支持纳秒时间戳和扩展属性如果盘是从很老的系统上来的inode 是 128 字节某些工具在读取扩展属性时会报错但正常读文件不受影响。5.2 关于 sync、VFS 与拔盘时机的实操心得热词里出现根文件系统、sync、vfs这几个词说明有不少人是在这个环节踩过坑的。这里说一下跨系统操作时的正确收尾顺序这一步做错前面的努力可能全白费。在 Linux 客户机里所有写操作完成后先sync然后卸载sudo umount /mnt/ext4umount会等待所有脏页写回、日志提交完成返回之后设备才真正处于安全状态。如果umount报target is busy说明还有进程占用用lsof D /mnt/ext4找出来或者fuser -mv /mnt/ext4看是谁杀掉之后再卸。绝对不要用umount -l偷懒那是懒卸载日志可能还没提交对可移动设备来说等于埋雷。客户机里卸载干净之后再回到 macOS 侧从虚拟机设置里取消 USB 设备勾选或者关机然后再拔线。顺序反了会怎样最典型的表现是下次挂载时e2fsck报一堆孤儿 inode 和目录项错误需要花时间修。数据能不能保住看运气我见过几次运气不好的日志区域被写坏最后只能从备份恢复。还有一点macOS 侧的本地 Time Machine 快照会占用不少空间有时候你明明往共享目录里拷了几十 GB 又删掉磁盘空间却没释放那不是 ext4 的问题是快照把数据块留住了。tmutil listlocalsnapshots /可以看需要的话用tmutil deletelocalsnapshots清理。这个跟主题关系不大但在一堆系统数据占用过大的求助里它是高频原因顺便提一句。6. 常见问题排查与数据安全底线6.1 高频问题速查问得最多的几个问题集中答一下。插上盘磁盘工具里什么都看不到只有一块未初始化——先换一根线和一个转接盒试试。很多便宜的 USB-SATA 桥接芯片在大容量盘或者特定分区表上会识别异常。换完还是不行在 Linux 里fdisk -l确认分区表是不是 GPT有些老盘用的是 MBR 加扩展分区macOS 的识别逻辑会挑食。ext4fuse 装好了挂载时提示 device not found——九成是 macFUSE 的内核扩展没被批准。去系统设置里找隐私与安全性往下滚会有一条被拦截的扩展通知点允许重启。Apple Silicon 用户记得先做降低安全性的那一步顺序错了会一直失败。虚拟机里能看到 sdb但 mount 说 unknown filesystem type——客户机内核没有加载 ext4 模块常见于精简版发行版或者容器镜像。modprobe ext4试一下不行就换个标准发行版的完整镜像。写入速度慢得离谱只有几 MB/s——检查是不是 USB 2.0 的口或者线。另外虚拟机磁盘缓存模式也有影响QEMU 里加cacheunsafe能提速但断电有风险我一般用默认的writeback折中。盘里有同名文件冲突拷贝时反复覆盖——多半是 macOS 的 APFS 默认大小写不敏感而 ext4 敏感。同一个目录里Readme.md和readme.md是两个文件拷到 macOS 上会互相覆盖。解决方式是先打包成tar再传或者拷到一个区分大小写的 APFS 卷里。6.2 我踩过的坑与最后几条经验这些年在这个问题上翻过几次车印象最深的一次是帮人恢复一台报废服务器的数据盘盘上开了 metadata_csum当时的 ext4fuse 直接读不了我又图省事没有做镜像直接在虚拟机里对着物理盘跑 fsck中途 USB 转接盒供电不足掉线客户机内核直接对着一块消失又出现的块设备继续操作结果超级块被写花。后来靠备份超级块和e2fsck -b 32768救回来一部分但丢了大概两天的数据。教训很直接任何时候动盘之前先做镜像镜像存在另一块物理设备上别存在同一块盘上。第二条经验是关于挂载点的。ext4fuse 的挂载点不要设在 iCloud Drive 同步目录或者任何被系统索引的路径下面Spotlight 会去扫那个目录触发大量随机读速度慢不说还有概率把 FUSE 进程卡死。放在~/mnt这种干净路径下同时用系统设置里的 Spotlight 隐私面板把挂载点排除掉。第三条是关于备份策略的。如果你有一块长期需要跨 macOS 和 Linux 使用的盘最省心的做法不是每次折腾驱动而是在盘上划分一个 exFAT 小分区做交换区真正需要保持 Linux 语义的数据放在 ext4 分区里通过虚拟机桥接。日常传文件走 exFAT 分区几秒钟搞定需要处理软链接、权限、特殊文件的时候再开虚拟机。这个组合我用了两年多基本没有再出过意外。最后提一个容易被忽略的细节如果你的外接盘是 SSD 且盒子支持 UASPmacOS 侧直通给虚拟机的时候客户机里记得确认一下 TRIM 是不是开了。ext4 在虚拟机里默认不一定开discard长期使用会掉性能。可以在挂载参数里加-o discard或者定期跑sudo fstrim -av。这个操作在移动硬盘上收益不明显但在 USB 3.2 的 NVMe 盒子上差别挺大我实测过一块 1TB 的盒子跑完 fstrim 之后随机写性能回升了将近一倍。