十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Linux下手动编译安装exFAT内核模块:解决U盘识别与4GB文件限制

Linux下手动编译安装exFAT内核模块:解决U盘识别与4GB文件限制 简介ExFAT是微软针对闪存设备优化的文件系统最大单文件可达16EB同时改善了大量小文件的读写效率弥补了FAT32在大容量存储上的不足。Linux内核不自带ExFAT支持需要借助第三方驱动。exfat-linux.tgz正是面向嵌入式Linux开发者的ExFAT驱动源码包已在海思HI3531dv200平台上验证通过适合安防监控、智能硬件或对内核文件系统机制感兴趣的开发者。资源共103个文件、压缩后约487KB包含22个c驱动源码、22个cmd脚本和11个示例文件同时提供DKMS配置、Kconfig及Makefile可直接编译为内核模块或并入内核源码树namei、super、inode等核心模块清晰展现了文件系统实现骨架。目前已有460人学习/下载。借助该资源读者能掌握驱动编译、加载以及mount挂载ExFAT分区的完整流程并通过具体实现细节深入理解文件系统缓存与簇分配逻辑包内附license与版权说明有助于在法律合规前提下评估商用可行性。 手上正好在调试一块嵌入式板子需要把超过4GB的固件镜像和离线数据包从开发机拷贝到移动硬盘里。U盘是exFAT格式Windows下用得好好的一插到Linux上直接懵了——系统不识别分区dmesg里一堆unknown filesystem。翻出很久以前存下来的exfat-linux.tgz手动编译加载驱动几分钟解决问题。这篇就把整个操作过程、背后的原理、以及我踩过的坑完整写出来给同样被exFAT折磨的Linux用户一个可复现的参考方案。1. 先搞清楚exFAT是什么以及Linux为什么默认不支持1.1 FAT32的4GB限制和NTFS的闪存尴尬如果你用过老一点的U盘或SD卡大概率遇到过这个问题拷一个高清电影超过4GB系统提示文件过大无法复制到目标文件系统。这就是FAT32的最大单文件大小限制4GB减1字节。这个限制在2000年前后没什么问题但现在一个手机备份、一个系统镜像、一段4K视频动辄就超过这个数。那为什么不直接用NTFSNTFS当然没有4GB限制但它是微软为机械硬盘设计的日志型文件系统。日志机制意味着频繁写入元数据对U盘、SD卡这类闪存介质来说一方面会加速损耗另一方面Windows默认还会开启NTFS的写入缓存如果直接拔U盘数据损坏的概率并不低。微软自己也意识到这个问题于是在2006年前后推出了专门为闪存设备优化的exFAT文件系统。1.2 exFAT的定位和核心特性exFAT的全称是Extended File Allocation Table本质上是FAT家族的一次现代化重构。它保留了FAT文件系统结构简单、跨平台兼容性好的优点同时把单文件大小上限从4GB提升到了理论上限16EBExabyte也就是1600万TB至少在未来很长一段时间内不会再撞上文件大小上限。空间管理上exFAT把簇大小从FAT32的32KB上限提升到了单簇最大32MB实际上位深更大大容量存储卡上空间利用率更高。同时它引入了空余空间分配表Allocation Bitmap格式化后不需要像FAT32那样频繁扫描整个分区来判断哪些簇是空的目录遍历和空间分配速度都有明显提升。但exFAT有个致命问题它是有专利的微软持有相关专利许可。Linux内核当然不能随便把别人的专利代码内置进来这也就是为什么很长一段时间里Linux下要读写exFAT都得走第三方方案这个exfat-linux.tgz就是其中之一。1.3 exfat-linux.tgz这个包到底是什么结合文件名和Linux社区的历史积累这个exfat-linux.tgz对应的是内核模块版exFAT驱动。和另一个常见的exfat-fuse方案不同内核模块版以.ko文件形式运行在内核态不经过用户态的FUSE文件系统层读写性能比FUSE版高不少。下面这张表可以快速区分两款主流方案对比项exfat-fuse (用户态)exfat-linux (内核模块)运行位置用户态FUSE进程内核态安装难度需要安装fuse库和工具需要内核头文件并编译模块读写性能中等FUSE转换开销大接近原生性能依赖的内核版本不挑版本需匹配内核版本编译适用场景临时挂载、内核源码不完整嵌入式、长期使用、性能敏感如果你在Linux 5.4以下版本用exFAT建议优先考虑内核模块版。Linux 5.4以上的内核已经集成了三星贡献的exfat官方驱动stexfat不需要自己编译了这点后面还会细说。2. 编译之前先把环境摸清楚2.1 确认你的内核版本和当前的exFAT支持情况动手编译前第一件事就是确认目标机器的内核版本以及是否已经存在exFAT驱动。依次执行下面几个命令uname -r cat /proc/filesystems | grep -i exfat lsmod | grep -i exfat modinfo exfat 2/dev/null | head -5在我常用的那台Ubuntu 18.04内核4.15上/proc/filesystems里没有exfatlsmod也查不到说明需要手动编译。如果你用的是CentOS 7老内核3.10或者一些嵌入式板子自带的内核2.6.32这种那更不用想官方内核直接不带exfat支持。注意一点如果modinfo exfat能查到但lsmod没有输出说明你的内核已经有exfat模块只是还没加载直接sudo modprobe exfat就能用不用往下折腾编译了。这种细节容易忽略建议先跑一遍命令再决定。2.2 编译工具的硬性要求内核模块的编译和普通应用程序不同它必须链接到当前内核的构建环境中所以依赖的关键包有这几个gcc和你内核编译时的编译器版本尽量一致make构建工具linux-headers-$(uname -r)当前内核的头文件这个最核心Ubuntu/Debian下安装sudo apt update sudo apt install gcc make linux-headers-$(uname -r)CentOS/RHEL下用sudo yum install gcc make kernel-devel-$(uname -r)这里有个需要特别提醒的地方linux-headers的版本必须和uname -r完全一致一点都不能差。我遇到过kernel-devel自动装了最新内核版本的头文件而系统实际跑的还是旧内核编译的时候报一堆Kernel configuration is invalid之类的错误。所以装完务必跑一下ls /usr/src/看看头文件目录是否对应当前内核版本。2.3 源码包的获取和解压我这里的exfat-linux.tgz是从内部资料盘里翻出来的实际大家可以从Linux内核模块的官方仓库或发行版源码镜像获取。按标准的tar包流程解压tar -zxvf exfat-linux.tgz cd exfat-linux解压后目录里通常有以下内容Makefile决定如何编译exfat_core.c、exfat_super.c等一系列.c源文件exfat.h、exfat_config.h等头文件README或INSTALL说明文件先打开README扫一眼。有的版本还区分KERNEL_DIR等编译参数如果README里提到需要指定内核源码路径那后面的make命令就要加参数。比如有的源码包要这样make KERNEL_DIR/lib/modules/$(uname -r)/build先花两分钟看README能省下后面半小时的排错时间。3. 从解压到开机自启完整编译安装流程3.1 编译和安装进入源码目录后直接执行make编译过程会输出一串CC编译命令和LD链接命令正常情况下几十秒就能完成嵌入式老机器可能要久一点。结束后目录下会出现一个exfat.ko文件这就是编译好的内核模块。接着安装到系统模块目录并加载sudo make install sudo depmod -a sudo modprobe exfatdepmod -a的作用是重新扫描模块依赖关系让modprobe能找到新安装的exfat.ko。如果这三步没有报错再跑一次lsmod | grep exfat就能看到模块已经加载了。一个细节make install默认会把exfat.ko拷贝到/lib/modules/$(uname -r)/extra/目录下但个别发行版对模块目录的扫描范围有限制。如果modprobe exfat之后提示找不到模块可以手动把模块复制到/lib/modules/$(uname -r)/kernel/fs/下再执行depmod -a。3.2 验证模块是否真的加载成功模块加载成功只是第一步真正验证能不能用还得看文件系统是否被识别。用lsmod确认外还要检查一下驱动是否注册了文件系统类型cat /proc/filesystems | grep exfat如果看到nodev exfat或者exfat字样前缀表示是否需要在块设备上说明文件系统已经注册成功了。到这一步内核态驱动的安装就算完成了。3.3 开机自动加载配置到这一步重启机器后发现U盘又不能用了原因是modprobe只是临时加载模块系统重启后不会自动加载。所以要把它固化到开机流程里。方式很简单在/etc/modules文件末尾追加一行sudo echo exfat /etc/modules这个文件会在系统启动时被kmod读取然后自动加载列表中的模块。嵌入式系统如果用的是systemd还有另一种更正规的写法在/etc/modules-load.d/下新建一个配置文件sudo bash -c echo exfat /etc/modules-load.d/exfat.conf两种方式效果一样我更推荐后者因为语义更清晰卸载时也方便。4. 模块装好之后赶紧验证读写和兼容性4.1 格式化U盘为exFAT驱动装好之后mkfs.exfat工具通常也跟着源码包安装了一些版本会同时编译出格式化工具。先查一下which mkfs.exfat如果没有这个工具需要单独安装exfat-utils或exfatprogs比如Ubuntu下sudo apt install exfat-utils确认设备名后格式化前一定要三思。假设U盘是/dev/sdb1可以用下面的命令格式化为exFATsudo mkfs.exfat -n MYUSB /dev/sdb1-n参数指定卷标这步会清空整个分区务必先lsblk或fdisk -l确认目标设备没错。我曾经在测试机上把/dev/sda系统盘当成了/dev/sdbU盘来格式化虽然系统盘挂了不心疼但那种一瞬间数据全无的感觉至今记得。4.2 挂载验证和读写测试格式化完成后再挂载sudo mkdir -p /mnt/usb sudo mount -t exfat /dev/sdb1 /mnt/usbmount时如果没有额外报错df -h应该能看到对应挂载点和容量。这时候就可以实际测试读写速度了我用一个大文件做基准dd if/dev/zero of/mnt/usb/test.bin bs1M count2048这个命令会向U盘写入一个2GB的测试文件bs1M表示每次读写1MBcount2048表示重复2048次。测完之后对比一下dd输出的写入速度。在我那台老笔记本上USB 3.0接口配普通U盘内核模块方案测出来的写入速度大约是110MB/s而之前用FUSE版本时只有70MB/s左右性能差距还是挺直观的。再验证一下大文件支持拷贝一个超过4GB的文件进去比如系统镜像cp linux.iso /mnt/usb/如果没有File too large之类的报错说明4GB限制确实已经不存在了。4.3 和Windows交叉使用的注意点exFAT最大的优势就是Windows和macOS开箱即用但交叉使用也不是完全没有注意点。Windows默认的exFAT格式化簇大小会根据分区容量自动调整比如32GB-256GB区间用128KB簇。在Linux下格式化时mkfs.exfat的默认簇大小也是一套自己的算法如果想让Windows下性能更好可以手动指定sudo mkfs.exfat -s 128 -n MYUSB /dev/sdb1-s参数指定每簇扇区数128扇区乘以512字节等于64KB。不过这里不用太纠结除非你做高并发小文件读写否则默认值已经够用。另外提一件事Windows下的快速格式化不会清空所有数据而Linux的mkfs.exfat默认就是完全重建文件系统。如果硬盘上有重要数据插到Linux上操作前一定先备份我见过太多因为只是想修复一下U盘结果整个盘清空的情况。5. 编译和使用中的常见问题与排查技巧5.1 编译报错Kernel configuration is invalid或找不到头文件这个错误90%是内核头文件没装对或者版本不匹配。先验证头文件是否就位ls /lib/modules/$(uname -r)/build如果这个目录不存在或指向空路径说明头文件缺失。Ubuntu下重装一个试试sudo apt install --reinstall linux-headers-$(uname -r)如果头文件在但还报错可能是头文件版本和当前内核不一致用uname -r和ls /usr/src对比一下确保安装的是同一个版本。5.2 加载模块时报module is already registered或Operation not permitted出现Operation not permitted最常见的原因是Secure Boot开启。内核在加载没有签名的第三方模块时会拒绝加载。解决方法有几个在BIOS里关闭Secure Boot最直接但有些机器不方便用mokutil导入MOK密钥给模块签名临时用modprobe加force参数不推荐破坏了签名验证嵌入式设备上如果不需要考虑安全启动策略直接在bootloader配置里关掉Secure Boot就完事了。PC上如果不想关可以用mokutil --import流程给模块签名步骤稍微繁琐但正规。5.3 挂载后只读无法写入这个现象在macOS格式化出来的exFAT分区上最容易出现。原因通常是分区表或者boot sector里的参数和Linux驱动的预期不一致。先看dmesgdmesg | grep -i exfat如果看到Volume was not unmounted cleanly之类的提示说明上次使用后没有安全弹出文件系统处于dirty状态。Windows下插入U盘后让它自动修复一下或者用fsck.exfat检查修复sudo fsck.exfat /dev/sdb1另外一些老版本内核模块对exFAT的主引导记录和备份引导记录不一致处理得不好修复后如果还是只读考虑升级一下驱动版本。5.4 拷大文件时速度快到一半突然卡住或报错这个我在USB 3.0的U盘上碰到过好几次。表面上是驱动不稳定实际多半是U盘本身的写入缓存策略问题。exFAT的驱动在挂载时默认使用wbwrite back模式也就是先写缓存再落盘突然拔U盘就会丢数据。最稳妥的做法是拷贝完执行sync命令或者直接umount卸载卸载成功才代表所有数据都落盘了另外如果频繁出现拷贝中途卡死可以检查一下U盘的温度和供电。USB hub供电不足时U盘会在高速写入中掉盘这是硬件问题换驱动根本解决不了。5.5 内核版本升级后模块失效这是手动编译内核模块最大的坑。一旦系统内核通过apt/yum自动升级/lib/modules/$(uname -r)路径就变了原来编译好的exfat.ko对应的内核版本和当前跑的内核不一致modprobe直接报Invalid module format。解决办法也是老一套升级内核后重新编译一次cd exfat-linux make clean make sudo make install sudo depmod -a sudo modprobe exfat如果不想每次升级内核都折腾就把系统对内核版本做锁定Ubuntu下用apt-mark hold linux-image-xxx或者干脆升级到Linux 5.4以上内核用内核自带的exfat驱动一劳永逸。5.6 常见问题速查表问题现象可能原因处理方式make报Kernel configuration invalid内核头文件缺失/版本不匹配重装linux-headers-$(uname -r)modprobe找不到exfat模块目录不在扫描范围复制到kernel/fs/目录后depmod -a加载时报Operation not permittedSecure Boot拦截关闭Secure Boot或签名模块挂载后只读文件系统dirtyfsck.exfat修复或Windows下安全弹出大文件写入卡住USB供电不足/缓存策略检查hub供电卸载前sync升级内核后模块失效版本不匹配重新编译或使用内核原生exfat6. 手动编译之外的另一个选择换个思路用原生exFAT6.1 Linux 5.4是个分水岭很多朋友可能不知道Linux 5.4内核开始已经集成了exFAT的官方驱动这也是三星贡献的代码。如果你的系统跑的是5.4以上的内核直接默认就支持exFAT完全不需要再编译第三方模块。判断方法很简单uname -r grep -i exfat /boot/config-$(uname -r)如果配置项是CONFIG_EXFAT_FSy或者CONFIG_EXFAT_FSm那官方驱动就已经在了前者直接支持后者modprobe exfat就能加载。所以这篇文章开头提到的exfat-linux.tgz更准确的定位是给老内核、嵌入式定制内核、或者不方便升级内核的场合做兼容用的方案。如果你的系统能轻松升级内核优先考虑升级到5.4省心得多。6.2 嵌入式场景下的取舍在嵌入式Linux上内核往往被裁剪过CONFIG_EXFAT_FS可能被手动关掉为了省存储空间这时候手动编译一个模块塞进去就是最务实的方案。但要注意两点第一嵌入式交叉编译时要选对编译器不能直接用PC上的gcc要用板子对应的交叉编译工具链否则编译出来的.ko文件在板上根本加载不了。第二嵌入式板子如果内核版本很老比如2.6.32exfat-linux.tgz这个源码包太新可能编译不过需要找和内核版本匹配的旧版驱动源码。这里可以查一下源码包里的CHANGELOG或者git log确认支持的内核范围。6.3 什么时候用FUSE版更合适如果只是临时挂载一次而且系统上已经装了exfat-fuse那直接用FUSE版也不亏免去编译的麻烦。命令行执行sudo mount.exfat-fuse /dev/sdb1 /mnt/usb但如果是长期使用、频繁传输大文件我还是建议内核模块版性能差距摆在那里。FUSE每次读写都要在内核态和用户态之间做上下文切换对小文件影响尤其明显几百个碎片文件的复制FUSE版比内核模块版慢一倍也正常。7. 实操下来的几点感受这套exFAT内核模块方案我用了好几年从Ubuntu 14.04到嵌入式板子都折腾过。最大的体会是能用官方内核原生支持就尽量用官方的省心太多。但如果你的环境确实卡在内核版本上exfat-linux.tgz这种内核模块方案是目前兼容性最好、性能最可观的选择。最近在调的一块板子内核是4.19的正好卡在原生exFAT支持之前把这份源码编译完扔进去U盘和移动硬盘读写都正常连续拷了几十GB的数据也没有出问题。如果你也在维护类似的老系统并且手头没有这份源码可以在能找到的内核模块仓库或者发行版源码包里找到对应版本的源码整个流程和我上面写的一模一样。最后再分享一个小技巧编译好的exfat.ko文件可以备份到一个固定目录比如/opt/exfat-backup/。这样每次系统内核升级后只要动态加载一下这个备用的模块文件就能临时恢复exFAT支持等哪天有空再重新编译一次完整的模块。毕竟内核模块这种事儿不在手边留一个备胎真到急用的时候就得现找源码现编译了。本文还有配套的精品资源点击获取
返回列表