TF卡FAT32与ext4双分区:对齐、格式化、挂载与避坑全流程

发布时间:2026/11/3 16:47:16
TF卡FAT32与ext4双分区:对齐、格式化、挂载与避坑全流程

一块128GB的TF卡,一半要给车机和相机读,一半要当某块ARM开发板的根文件系统跑ext4,这事听着简单,真动手的时候能让人卡住一整个下午。我上周就陪着朋友折腾了一回:先是分区软件里切完区,Windows弹窗说"使用驱动器前需要格式化";换到Linux下blkid能看到两个分区,但ext4那块挂上去没两分钟变只读;最后发现是分区没做扇区对齐,加上ext4的日志和挂载参数全用的默认值。这也正是"TF卡分区成FAT32和ext4分区"这个操作看着基础、坑却密集的原因——它不只是打开分区软件点两下,而是要把分区表类型、起始扇区对齐、簇大小、文件系统参数、挂载选项这几件事一次性想清楚。

这篇内容面向的是手上有大容量TF卡、又同时存在"通用设备识别"和"Linux/类Linux系统读写"两种需求的场景:单板计算机的启动卡、外置应用迁移分区、行车记录仪加数据盘、掌机双系统、路由器外挂存储扩容都算。哪怕你之前只会在Windows里点"格式化",照着下面的顺序走一遍也能落地,我会把每一步"为什么这么选"讲透,而不只是丢一串命令。

1. 先把容量账算清楚:两个分区各自要多大

分区这件事最容易翻车的地方不在命令,而在动手前的规划。很多人拿到卡就一刀切成"一半一半",结果跑起来发现ext4那边塞不下系统镜像,或者FAT32那边放两个4K视频就满了。容量怎么切,完全取决于这块卡上两个分区各自承担什么职责,而这个职责是被"谁会来读它"决定的。

1.1 从使用场景倒推容量配比

我一般把使用场景归成三类,配比思路完全不同。

第一类是启动卡型:FAT32分区放引导文件和固件,ext4分区放根文件系统。这类场景的FAT32分区通常很小,因为引导文件加起来往往不到1GB(内核镜像、设备树、配置文件),但不能切得太抠,建议留2–4GB,理由是升级固件、临时塞几个镜像、放个overlay脚本都很吃空间,切到刚好够用的地步,下次想加东西就得重新分区。ext4分区吃掉剩下的全部。

第二类是数据共享型:FAT32分区是主战场,放照片、视频、文档,ext4分区只是给某个Linux程序做数据落盘或者给应用迁移工具当外挂。这种情况FAT32应该占七成以上,因为FAT32是"通用语言"——相机、车机、打印机、老式播放器、各类嵌入式设备基本都认它,而ext4在Windows下默认不可见。ext4那边留10–20GB给应用和数据就够了。

第三类是对半开的双系统型:两个分区都要长期写数据,那就按实际数据量估算,再各留20%余量。这里有个坑要提醒:TF卡写满之后性能会断崖式下跌,尤其是廉价卡,主控在剩余空间不足时垃圾回收效率骤降,写入速度可能掉到原来的十分之一。所以无论哪种场景,都别把分区切到"一点不剩"。

使用场景FAT32建议容量ext4建议容量备注
开发板启动卡(64GB卡)2–4GB剩余全部FAT32只放引导文件,别小于1GB
相机/车机 + 数据盘(128GB卡)90–110GB10–20GBFAT32为主,兼容性优先
应用迁移外挂(64GB卡)40GB20GBext4分区给应用迁移工具用
双系统掌机(256GB卡)100GB140GB两边都要留20%余量

1.2 FAT32那个"32GB上限"到底卡在哪

几乎所有人都听过"FAT32最大32GB",但这个说法其实是个流传很广的误解——它不是文件系统的限制,是Windows格式化工具的限制。FAT32规范本身支持的卷可以到2TB级别,Linux下的mkfs.vfat给128GB的卡格式化成FAT32毫无压力。

真正硬性的限制只有一条:单个文件不能超过4GB减1字节。这一条没法绕过,只能换exFAT。所以如果你的场景里有大体积视频文件(比如行车记录仪的循环录像),要么切成多段,要么干脆整个分区用exFAT——但代价是老设备可能认不出来。

那Windows为什么限制在32GB?历史原因,早年设计时认为大容量存储应该走NTFS,就没在图形界面里给FAT32放开。你可以用命令行format /FS:FAT32强行格式化更大容量,但超过32GB后簇大小会变得很粗,空间浪费严重。这也是我推荐在Linux下用mkfs.vfat做FAT32格式化的原因:它能让你自己指定簇大小,把浪费压到最低。

1.3 MBR还是GPT,这个选择影响后面所有步骤

分区表类型决定了后面分区工具的用法,也决定了Windows能不能正常识别。

**MBR(msdos)**是这类卡的事实标准。它最多支持4个主分区,单盘最大2TiB,兼容性最好——几乎所有嵌入式固件、老设备、Windows的可移动介质识别逻辑都是围绕MBR写的。给TF卡做FAT32+ext4双分区,一律选MBR,除非你的卡超过2TB(目前消费级TF卡还远没到)。

GPT的优势是分区数量多、有备份分区表、支持超大容量,但它在可移动介质上的兼容性会打折扣:一部分老设备的引导程序压根不认GPT,某些Windows版本对可移动GPT介质的挂载行为也不一致。我实测过一块用GPT分区的卡插进某款车机,车机直接显示"无存储设备",换成MBR立刻就正常了。

提示:如果你已经用GPT分过区又想改回MBR,不要直接mklabel msdos了事,先把卡里要留的数据拷出来。改分区表类型会重写前34个扇区,原有分区的起始位置信息全部丢失,数据虽然在物理上还在,但恢复起来很折腾。

2. 分区表落地:对齐、顺序和一个不能错的目标盘

规划清楚之后进入实操。这一步最容易出的不是技术错误,而是低级错误——把系统盘当成TF卡给格了。我见过不止一个人在执行mkfs的时候/dev/sdX写错一位,把工作机的数据盘送走。所以在敲任何写操作命令之前,先把目标设备确认三遍。

2.1 用三个信号交叉确认目标设备

插上读卡器之后,别急着看/dev/sdb还是/dev/sdc,用下面这组命令交叉验证:

lsblk -o NAME,SIZE,TYPE,TRAN,MOUNTPOINT,MODEL

重点看三列:TRAN是usb说明走的是USB读卡器,SIZE要和你手上卡的标称容量对得上(128GB的卡实际显示119.2GiB左右是正常的,因为厂商按1000进制标、系统按1024进制算),MODEL通常是读卡器芯片的型号。

再看一眼容量:

sudo blockdev --getsize64 /dev/sdb

输出是字节数,128GB卡大约是127865454592这个量级。如果算下来只有标称容量的六成甚至更低,那这张卡大概率是扩容卡(假容量),这时候分区没有任何意义,先用f3probe之类的工具验一下真实容量。

最后确认没有挂载:

lsblk /dev/sdb

如果有分区挂在/media或者/mnt下面,先umount掉,否则分区表写入会失败或者出现"设备忙"。

检查项命令正常表现异常信号
设备类型lsblk -o TRAN显示usb显示sata/nvme说明选错盘
实际容量blockdev --getsize64接近标称值的93%左右明显偏小可能是扩容卡
挂载状态lsblk无MOUNTPOINT有挂载点需先卸载
分区表sudo parted /dev/sdb print显示现有分区和标签类型报错可能是分区表损坏

2.2 用parted切出两个分区

我习惯用parted而不是fdisk,原因是它的--script模式可以直接写进脚本,而且单位能用MiB、GiB这种人类可读的形式,不用自己算扇区号。

# 1) 写入全新的MBR分区表(会清空原有分区信息) sudo parted /dev/sdb --script mklabel msdos # 2) 第一个分区:FAT32,从1MiB开始,到4GiB结束 sudo parted /dev/sdb --script mkpart primary fat32 1MiB 4GiB # 3) 第二个分区:ext4,从4GiB开始,到卡尾 sudo parted /dev/sdb --script mkpart primary ext4 4GiB 100% # 4) 设置分区类型ID(对Windows识别很关键) sudo parted /dev/sdb --script set 1 lba off sudo parted /dev/sdb --script set 1 boot on # 5) 刷新内核分区表缓存 sudo partprobe /dev/sdb

几个细节值得说清楚:

起始位置写1MiB而不是0,这是对齐要求,下面单独讲。第二个分区的起点和第一个的终点用同一个值(4GiB),中间不留空隙,避免产生未分配空间。**set 1 lba off**这一句是把FAT32分区的LBA标志关掉——某些老设备的引导程序看到LBA标志会走不同的读取路径,关掉兼容性更好;不过如果你的设备明确要求LBA,改成on。

如果你更习惯交互式的fdisk,逻辑是一样的,只是要自己换算扇区:1MiB = 2048扇区,4GiB = 8388608扇区。分区类型用t命令设,FAT32 LBA是c,Linux是83。

sudo fdisk /dev/sdb # o 新建空MBR分区表 # n → p → 1 → 2048 → +4G 第一个分区 # n → p → 2 → 回车 → 回车 第二个分区吃掉剩余空间 # t → 1 → c 第一个分区标记为FAT32 LBA # t → 2 → 83 第二个分区标记为Linux # w 写入

2.3 为什么起始扇区一定要1MiB对齐

这是整个流程里最容易被忽略、后果又最实在的一步。

TF卡内部的闪存页大小通常是8KB或16KB,主控在做写入时会以页为单位操作。如果分区的起始位置没有和闪存的物理块边界对齐,那么每一次跨边界的写入都会触发"读-改-写":先把整个物理块读出来,改掉其中一部分,再擦除整块写回去。一次逻辑写入变成三次物理操作,写放大直接翻倍,寿命和速度双杀。

早期的分区工具默认从第63扇区开始(那是几十年前硬盘的CHS几何遗留),63×512 = 32256字节,不是4KB的整数倍。现代工具基本都默认1MiB对齐了,但如果你用了一些老版本软件或者手动指定扇区号,很容易踩回去。

判断标准很简单:起始扇区号能被2048整除(512字节逻辑扇区下)就是1MiB对齐。用parted检查:

sudo parted /dev/sdb align-check optimal 1 sudo parted /dev/sdb align-check optimal 2

两条命令都返回aligned才算过关。返回not aligned就得删掉重建。

提示:现在很多TF卡的逻辑扇区是512字节,物理扇区是4KB甚至更大(所谓512e)。对齐到1MiB在两种情况下都安全,因为它同时是4KB、8KB、16KB、64KB的整数倍。别为了"省那1MiB"把起点设在2048扇区之前。

2.4 分区顺序不是随便排的,FAT32必须在前

分区表里两个分区的先后顺序,在Linux下无所谓,但在设备端差别巨大。

很多嵌入式固件和简易系统(车机、老式播放器、某些相机的存储扫描逻辑)只扫描分区表里的第一个条目,甚至只看物理上最靠前的那个分区。你把ext4放在前面、FAT32放在后面,插进这类设备就是"未检测到存储卡"。

还有一种情况是Windows:对于可移动介质,Windows的挂载逻辑历史上只处理分区表里的第一个分区,后面的分区即使格式化成NTFS也不一定分配盘符。虽然新版系统有所改善,但把FAT32放第一个分区是最省心的做法。

所以规矩就是一句:FAT32永远排第一,ext4排第二。如果你现在的布局反了,不要试图用工具"调整顺序",直接备份数据重新分区,因为分区表条目的顺序和分区数据区的物理位置是绑定的。

3. 格式化参数:簇大小、保留块和日志的取舍

分区表写对只是搭好了架子,文件系统参数才决定这块卡跑起来顺不顺。这一步的默认值往往不适合闪存介质,尤其是ext4——它是为机械硬盘设计的,直接套默认参数用在TF卡上,写放大会明显偏高。

3.1 FAT32的簇大小直接决定空间浪费率

FAT32的分配单位是"簇",一个文件哪怕只有1字节,也要占满一整簇。簇越大,大文件读写越连续、FAT表越小,但小文件浪费越严重;簇越小则相反。

mkfs.vfat的-s参数指定"每簇扇区数",512字节扇区下,-s 8就是4KB簇,-s 64就是32KB簇。下面这张表是我常用的对应关系:

分区容量推荐簇大小-s参数空间浪费率(小文件多时)
≤ 8GB4KB-s 8低
8–16GB8KB-s 16较低
16–32GB16KB-s 32中等
32–64GB32KB-s 64较高
64GB以上64KB-s 128高,但FAT表小、大文件快

为什么大容量要配大簇?因为FAT32的FAT表项数量有上限(约2.68亿个),簇太小会导致FAT表本身占掉大量空间,而且挂载时扫描FAT表的时间变长。64GB的分区如果用4KB簇,FAT表会有1600多万个表项,占60多MB,完全是浪费。

实际格式化命令:

# 4GiB的引导分区,16KB簇 sudo mkfs.vfat -F 32 -n BOOT -s 32 /dev/sdb1 # 100GB的数据分区,64KB簇 sudo mkfs.vfat -F 32 -n DATA -s 128 /dev/sdb1

-F 32是强制指定FAT32(不写的话工具会按容量自动选,大容量可能给你选FAT32也可能报错),-n是卷标。

3.2 ext4在闪存上要改的三个参数

mkfs.ext4的默认参数有三个地方对TF卡不友好,我一般都会改:

sudo mkfs.ext4 -L ROOT -m 1 -O ^has_journal -E lazy_itable_init=0 /dev/sdb2

-m 1:保留块比例从默认的5%降到1%。保留块的初衷是给root用户留应急空间、减少碎片,但在几十GB的分区上5%就是几个GB白扔。1%已经足够,太小的分区(<8GB)可以干脆设成-m 0。

-O ^has_journal:关掉日志。这是最有争议的一个参数,得说清楚代价。ext4的日志机制会在每次元数据变更时先写日志区再写数据区,等于同一份元数据写两遍,在闪存上就是双倍写放大。关掉之后文件系统退化成"ext2式的行为",性能提升明显,但掉电或拔出时会留下不一致状态,必须跑fsck修复,严重时可能丢文件。

我的取舍是:如果是数据盘、内容可重新生成(比如缓存、临时文件、应用数据),关日志;如果是系统根分区、里面有配置和代码,保留日志,改用-J size=4把日志区缩小到4MB,这样写放大可控,掉电也不会太惨。

-E lazy_itable_init=0:让inode表立即初始化,而不是交给内核在后台慢慢做。代价是格式化时间变长(大分区可能要几分钟),好处是第一次挂载时不会因为后台初始化而出现明显的IO抖动。

还有一个参数值得考虑:-T small预设。它会把inode大小从256字节降到128字节、每inode字节数调小,适合小文件极多的场景(比如放一堆源码)。但如果你主要放大文件,默认的-T default更好,因为大inode能存扩展属性、支持纳秒时间戳。

参数默认值建议值改的理由代价
-m5%1%(小分区0%)回收被保留块吃掉的容量极端情况下root无应急空间
-O has_journal开启数据盘关闭,系统盘保留减少元数据双写掉电后需fsck,可能丢文件
-J size随容量4–16MB控制日志区占用日志区太小可能频繁checkpoint
-E lazy_itable_init10避免首次挂载IO抖动格式化时间变长
-i(每inode字节数)16384小文件多用8192避免inode耗尽占用更多空间

3.3 卷标是两个系统之间的"接头暗号"

卷标看起来是个可有可无的装饰,但在双分区场景里它非常有用——因为设备名(/dev/sdb1)会随着插入顺序变化,而卷标是稳定的。

FAT32的卷标最多11个字符,只能大写字母、数字和少数符号;ext4的卷标最多16字节,支持大小写和中文(但中文卷标在挂载时可能编码出问题,不建议)。我给的建议是全部用大写英文加短横线,比如BOOT、DATA、LINUX-ROOT,避免空格和特殊字符。

设置方式有两种,格式化时用-n或者事后用工具改:

# 格式化时指定 sudo mkfs.vfat -n BOOT /dev/sdb1 sudo mkfs.ext4 -L LINUX-ROOT /dev/sdb2 # 事后修改 sudo fatlabel /dev/sdb1 BOOT sudo e2label /dev/sdb2 LINUX-ROOT

改完之后lsblk -o NAME,LABEL就能看到,挂载的时候可以用LABEL=BOOT代替设备名,这样换读卡器、换USB口都不会影响。

4. 挂载配置:让ext4分区每次插上就自动就位

格式化完成之后,FAT32分区插到Windows或者Linux上一般都能自动挂载,麻烦的是ext4分区——它需要明确指定挂载点,而且如果要在每次启动时自动挂载,就得写fstab。这一节把fstab的几个字段和闪存友好的挂载选项讲清楚。

4.1 用UUID而不是设备名做标识

/dev/sdb2这种设备名是不稳定的。系统里插了多个USB设备、读卡器换了USB口、甚至重启顺序不同,都可能让这块卡从sdb变成sdc。用设备名写fstab,某天开机就可能挂错盘或者挂载失败。

正确做法是用UUID或者PARTUUID。查询:

sudo blkid /dev/sdb2

输出类似:

/dev/sdb2: LABEL="LINUX-ROOT" UUID="3f8a1c2e-7b4d-4a91-9e2f-5c6d8b0a1f37" TYPE="ext4"

FAT32分区的UUID格式不一样,是1234-ABCD这种短格式。把它们复制进fstab:

UUID=3f8a1c2e-7b4d-4a91-9e2f-5c6d8b0a1f37 /mnt/root ext4 defaults,noatime,commit=120 0 2 UUID=1234-ABCD /mnt/boot vfat utf8,uid=1000,gid=1000,umask=0002,noatime 0 2

4.2 fstab六个字段逐项拆解

很多人写fstab是抄来的,出问题不知道从哪查。其实六个字段各有明确含义:

字段含义本例取值说明
1设备标识UUID=...也可写LABEL=或PARTUUID=
2挂载点/mnt/root目录必须已存在
3文件系统类型ext4/vfat写错会导致挂载失败
4挂载选项noatime,commit=120逗号分隔,见下表
5dump备份标志0基本不用,写0
6fsck顺序ext4写2,vfat写0根分区是1,其他2,不检查0

第6字段有个细节:vfat分区不要做开机fsck(写0),因为fsck.vfat在发现不一致时行为比较激进,可能直接改坏数据。ext4写2表示在根分区检查完之后检查。

4.3 闪存友好的挂载选项组合

默认的defaults包含relatime、rw、suid、dev、exec、auto、nouser、async,对TF卡来说还不够,我一般补这几项:

sudo mount -o noatime,commit=120,errors=remount-ro /dev/sdb2 /mnt/root

noatime:不更新文件的访问时间。默认的relatime已经比atime好很多(只在访问时间早于修改时间或超过一天时更新),但noatime是彻底的,每次读文件不产生任何写入。对闪存来说,这能砍掉相当一部分无谓的写操作。

commit=120:日志提交间隔从默认5秒拉长到120秒。间隔越长,写放大小、性能好,但掉电丢失的窗口越大。数据盘可以用120甚至300,系统盘建议60以内。

errors=remount-ro:遇到文件系统错误时自动重挂为只读,而不是继续写导致错误扩散。这一条在TF卡上很重要——卡老化之后会出现坏块,只读模式能让你及时发现问题而不是静默损坏数据。

关于discard:很多教程会建议加上discard开启在线TRIM。我的建议是别加。原因有两个:一是大量TF卡的主控压根不支持TRIM,加了会在日志里刷discard operation not supported的警告;二是在线TRIM会在删除文件时立即触发擦除命令,反而增加主控负担、拖慢写入。更好的做法是用fstrim定期手动或定时清:

# 手动跑一次 sudo fstrim -v /mnt/root # 或者交给systemd定时器,每周跑一次 sudo systemctl enable --now fstrim.timer

如果fstrim报the discard operation is not supported,说明这张卡确实不支持,那就不折腾了,正常用就行。

挂载选项作用是否推荐适用场景
noatime不记录访问时间强烈推荐所有闪存介质
commit=120拉长日志提交间隔推荐(数据盘)写入频繁的数据盘
errors=remount-ro出错转只读强烈推荐所有场景
discard在线TRIM不推荐仅在确认卡支持时考虑
sync同步写入禁止会让写入速度掉到1/10
data=writeback数据不排序谨慎有掉电风险,仅缓存盘用

5. Windows那一侧看到什么:可见性与误操作防范

分区做完,插回Windows,很多人第一反应是"怎么只有一个盘"。这不是做错了,是正常现象——但这个"正常现象"背后有几个必须知道的风险点,不搞清楚很容易把ext4分区当成"未分配空间"给格了。

5.1 Windows只挂载第一个分区的原因

Windows对可移动介质(U盘、SD卡、读卡器)的挂载逻辑,历史上只处理分区表里的第一个条目。这个设计源自软盘时代"一个介质一个卷"的假设,后来虽然支持了多分区,但对"可移动"这一类设备的处理策略一直没完全放开。

结果是:FAT32在第一个位置,Windows正常显示D:;ext4在第二个位置,Windows的资源管理器里完全看不到。打开"磁盘管理",你会看到这块卡显示为两个分区,第一个是FAT32,第二个标着"未知分区"或者干脆显示为未分配。

关键点:千万不要在磁盘管理里对那个"未知分区"点右键做任何操作。某些版本的磁盘管理会提示"初始化磁盘"或者"删除卷",一旦执行,ext4分区的分区表条目就没了。

5.2 第三方ext4驱动的真实风险

想在Windows下读写ext4,得装第三方驱动。这类工具确实能用,但我对它的定位很明确:只读可以,写入要极其谨慎。

原因是ext4的文件系统特性(extent树、延迟分配、日志)在Windows下的实现完整度参差不齐,写入操作一旦处理不当,轻则文件时间戳错乱,重则整个文件系统结构损坏。我遇到过最典型的情况是:在Windows下往ext4分区拷了几个文件,回到Linux下fsck报了一堆inode错误,虽然最后修复了,但丢了几个文件。

如果确实需要在两个系统之间交换数据,正确的思路是用FAT32那个分区当中转站,而不是让Windows去碰ext4。这也回到了第1章的容量规划——FAT32分区要留足空间,正是为了承担这个职责。

5.3 防止"需要格式化"弹窗的三道防线

插卡时Windows弹"使用驱动器前需要格式化",是最常见的恐慌时刻。这个弹窗通常有三种成因,对应三种处理:

成因一:分区表条目类型不对。比如FAT32分区的类型ID写成了0x83(Linux),Windows就不认。用fdisk把类型改回c即可,数据不受影响。

成因二:文件系统确实损坏。比如上次没安全弹出就拔卡。这种情况在Linux下跑sudo fsck.vfat -a /dev/sdb1修复,不要在Windows里点"格式化"。

成因三:卡本身进入只读或半损坏状态。如果Linux下也报IO错误,那基本是卡的问题,先做镜像备份再说。

提示:养成"安全弹出"的习惯,对TF卡寿命的正面影响比任何参数调优都大。拔卡时正在进行的写入会被截断,FAT表和ext4日志都可能留下半截状态。Windows下用托盘图标弹出,Linux下用udisksctl unmount -b /dev/sdb1配合udisksctl power-off -b /dev/sdb(后者会让读卡器断电,确保没有缓存残留)。

6. 踩坑实录:分完区之后最常见的几个翻车现场

前面讲的是"怎么做对",这一节讲"做完了不对怎么办"。下面这几个问题我都真实遇到过,排查链路完整写出来,你可以照着顺序复现。

6.1 分区表写不进去,或者写完插拔就还原

现象:parted执行完没报错,partprobe也过了,但拔插一次之后分区又变回原来的样子。

排查链路:

第一步看内核有没有真的重新读分区表。sudo partprobe /dev/sdb之后立刻lsblk /dev/sdb,如果分区已经变了,说明是写缓存没刷。执行sync再拔卡。

第二步看是不是卡进入了写保护状态。SD卡侧面有个物理拨杆,拨到Lock位置就是只读。另外,很多卡在检测到闪存寿命耗尽或者坏块过多时会自动进入永久只读模式(这是主控的自我保护机制),这时候任何写操作都会被静默忽略——注意是"静默",工具可能不报错。

验证方法:

# 看内核有没有报只读 dmesg | tail -30 | grep -i "read-only\|write protect" # 直接试写,看是否报错 sudo dd if=/dev/zero of=/dev/sdb bs=512 count=1 conv=fsync

如果dd报Read-only file system或者Operation not permitted,基本可以确认是写保护或者卡已锁死。

第三步,如果卡是新的、拨杆也在正常位置,检查读卡器。有些廉价读卡器对大于32GB的卡支持不好,写入分区表会失败。换一个读卡器试一次,这一步能排除掉相当一部分"玄学问题"。

6.2 分完区容量对不上,少了好几个GB

现象:128GB的卡,两个分区加起来只有110GB,剩下十几GB不知道去哪了。

成因排查:

先看是不是分区表里的未分配空间。sudo parted /dev/sdb unit MiB print free,输出里会明确列出Free Space的位置和大小。如果第二分区没到100%,那部分就是白扔的。

再看文件系统开销。ext4默认会占用一部分空间做inode表、日志区、保留块,df -h显示的可用容量比分区容量小几个GB是正常的。用sudo tune2fs -l /dev/sdb2 | grep -i "block count\|reserved"能看到具体分配。

最后看簇浪费。FAT32分区如果簇设得太大(比如64KB),而里面全是几十KB的小文件,浪费率可能到50%。df显示的是簇占用,不是实际文件大小。用du --apparent-size对比一下就知道了。

现象可能原因验证命令处理
分区总和小于卡容量末尾有未分配空间parted print free扩展第二分区或重建
ext4可用空间小于分区inode表+日志+保留块tune2fs -l正常现象,可用-m 1优化
FAT32空间消耗异常快簇太大+小文件多du --apparent-size重新格式化为小簇
卡实际容量远小于标称扩容卡f3probe换卡,别存重要数据

6.3 设备端只认FAT32分区,ext4分区完全隐形

这个是预期行为,不是故障。绝大多数车机、相机、打印机、老式播放器的存储扫描逻辑只处理第一个分区,而且只识别FAT/exFAT。

如果你需要设备端同时用两个分区,那就得确认这个设备是否支持多分区挂载。支持的情况通常是:设备本身跑Linux(很多智能车机、部分播放器),会在启动时扫描所有分区;不支持的情况,只能把数据都放FAT32那边。

有一个折中的办法:在FAT32分区里建目录来分类,虽然失去了ext4的权限管理和日志保护,但对纯数据存储来说影响不大。

6.4 用着用着ext4分区变成只读

现象:前几天还好好的,某天开始往ext4分区写文件报Read-only file system。

这是TF卡最典型的故障前兆,排查顺序如下:

# 1) 看内核日志里的IO错误 dmesg | grep -i "I/O error\|ext4-fs error\|remount" # 2) 看文件系统状态 sudo tune2fs -l /dev/sdb2 | grep -i "filesystem state" # 3) 挂载状态里有没有ro mount | grep sdb2

如果dmesg里出现EXT4-fs error (device sdb2): ... remounting filesystem read-only,说明文件系统检测到了元数据不一致,主动保护性转只读。这时候要做的是:

第一步,立刻停止写入,把能读的数据拷出来。别急着fsck,因为修复过程可能删除它认为"不一致"的文件。

第二步,卸载后跑只读检查:sudo fsck.ext4 -fn /dev/sdb2。-n表示只检查不修改,先看看问题有多大。

第三步,如果只是日志回放问题,用-p自动修复:sudo fsck.ext4 -p /dev/sdb2。如果真的修不好,再用-y(但要清楚这意味着所有提问都回答yes,可能删文件)。

第四步,修复完之后立刻做镜像备份:sudo dd if=/dev/sdb of=card-backup.img bs=4M status=progress。因为出现这种错误的卡,通常已经在走下坡路,随时可能彻底挂掉。

6.5 一个容易被误判的假故障:ext4分区同时挂两个地方

有次一个朋友说他的卡"写进去的文件过一会儿就没了"。查了半天发现,他把同一个ext4分区同时挂在了两个挂载点(一个通过fstab开机自动挂,另一个是手动mount的),两个挂载点各有一套缓存,互相覆盖。

ext4不像FAT32那样允许随意重复挂载同一设备到不同位置,虽然内核会阻止大部分情况,但通过bind mount或者不同的命名空间还是能造出来。

养成习惯:挂载前先findmnt /dev/sdb2确认没有已存在的挂载,写完数据用sync再卸载。另外fstab里给分区加个nofail选项,卡没插的时候开机不会卡在emergency shell:

UUID=3f8a... /mnt/root ext4 defaults,noatime,nofail,x-systemd.device-timeout=5s 0 2

x-systemd.device-timeout=5s让systemd最多等5秒,超时就跳过,避免开机卡住。

7. 备份、验证和一次简单的写入实测

分区格式化这类操作有个特点:做对了一次就再也不需要重做,但做错一次可能损失全部数据。所以在收尾之前,我一般会做三件事:备份分区表、跑一遍验证清单、做一次写入测试确认性能没有异常。

7.1 备份分区表比备份整卡更实用

整卡镜像动辄几十上百GB,备份一次很费时间。日常更实用的是只备份分区表——它只有几KB,但包含了恢复所需的关键信息:

# 备份MBR分区表(前512字节)和分区表详情 sudo dd if=/dev/sdb of=sdb-mbr.bak bs=512 count=1 sudo sfdisk -d /dev/sdb > sdb-partition.txt # 恢复时 sudo sfdisk /dev/sdb < sdb-partition.txt

sfdisk -d导出的文本文件长这样:

label: dos label-id: 0x1a2b3c4d device: /dev/sdb unit: sectors /dev/sdb1 : start= 2048, size= 8388608, type=c /dev/sdb2 : start= 8390656, size= 241172480, type=83

这个文件的价值在于:如果哪天分区表被误写,只要数据区没被动过,用这个文件重建分区表就能把数据找回来。因为文件系统的超级块还在原来的位置,mount的时候能正常识别。

如果你确实需要整卡镜像,注意两点:一是镜像文件的大小会等于卡的原始容量(128GB的卡就是128GB的镜像,哪怕实际只用了10GB),二是可以用gzip或zstd边压边存:

sudo dd if=/dev/sdb bs=4M status=progress | zstd -T0 -3 > card-backup.img.zst

7.2 上线前的验证清单

做完分区格式化,别急着往里面拷数据,先按下面这张表过一遍:

# 1) 分区表和对齐 sudo parted /dev/sdb unit MiB print free sudo parted /dev/sdb align-check optimal 1 sudo parted /dev/sdb align-check optimal 2 # 2) 文件系统识别 sudo blkid /dev/sdb1 /dev/sdb2 # 3) 文件系统完整性(只检查不修改) sudo fsck.vfat -n /dev/sdb1 sudo fsck.ext4 -fn /dev/sdb2 # 4) 实际挂载测试 sudo mkdir -p /mnt/test-boot /mnt/test-root sudo mount /dev/sdb1 /mnt/test-boot sudo mount /dev/sdb2 /mnt/test-root df -hT /mnt/test-boot /mnt/test-root
检查项通过标准不通过的典型原因
对齐检查两个分区都返回aligned起始扇区不是2048的倍数
blkid识别分别显示TYPE="vfat"和TYPE="ext4"格式化没成功或分区类型ID错
fsck检查无错误输出,返回0格式化中断或卡有坏块
挂载测试能挂上且df显示正确容量驱动缺模块或fstab写错
写入测试能创建文件并sync成功写保护或卡容量异常

7.3 一次简单的写入实测

最后做一次写入测试,主要是确认两件事:实际写入速度是否正常,以及分区是否真的能落盘。

# 顺序写入测试:写1GB数据看速度 dd if=/dev/zero of=/mnt/test-root/testfile bs=1M count=1024 conv=fsync status=progress # 清理 rm /mnt/test-root/testfile # 小块随机写入测试(模拟日常使用) fio --name=randwrite --ioengine=libaio --rw=randwrite --bs=4k \ --size=256M --numjobs=1 --runtime=30 --time_based \ --filename=/mnt/test-root/fiotest --direct=1

参考值:一张标称U3 A2的卡,顺序写入应该在60–90MB/s,4K随机写入在2–5MB/s这个量级。如果顺序写入只有十几MB/s,先换读卡器再测——读卡器是整条链路上最容易被低估的瓶颈,很多老读卡器只支持USB 2.0,速度上限就是40MB/s左右。

FAT32分区也测一下,重点看簇大小的影响:往一个64KB簇的FAT32分区里写一万个4KB小文件,速度会比4KB簇的分区慢很多,因为每个文件都要占满一整簇,实际写入量被放大了16倍。

# 小文件测试:创建1000个4KB文件 mkdir -p /mnt/test-boot/smallfiles time (for i in $(seq 1 1000); do dd if=/dev/zero of=/mnt/test-boot/smallfiles/f$i bs=4k count=1 conv=fsync 2>/dev/null; done) sync

如果这一步耗时超过30秒,说明簇大小选得太大,或者卡的小文件性能确实不行。前者可以重新格式化为更小的簇,后者只能接受——TF卡的主控就是为顺序读写优化的,小文件随机写本来就是它的短板。

补一个我自己的经验:给这类双分区卡做长期使用,最好每半年做一次"体检"——把重要数据备份出来,跑一遍完整的fsck,看一眼dmesg里有没有积累的IO错误,再用f3read之类的工具扫一遍坏块。TF卡的故障往往是渐进的,早期只是偶尔的写入重试,等到开始报IO错误的时候,留给你的时间窗口通常只剩几天。分区参数调得再好,也挡不住物理老化,这一点上老老实实做备份,比任何优化都管用。