落雨宸的时光机
1202 字
6 分钟
记一次由于 GPT 分区表冲突导致的重启后 RAID 设备消失,附 NixOS 下 RAID 挂载和磁盘休眠的配置
2025-09-08
...

没耐心请直接看结论部分。

引言#

弄了点硬盘打算组建 RAID 阵列,根据网上的教程和 Gemini 的提示,用 mdadm 创建了一个 RAID 0 阵列。能正常读写文件了,又摸索着设置了开机自动挂载。

重启设备试试自动挂载正常不正常,结果 SSH 连不上了。赶紧拿电视当显示器艰难 Debug,一打开就是 Emergenct Mode 😇。systemd 启动失败,挂载 /mnt/raid0 失败,等待设备 /dev/md0 超时。

排查#

怀疑 1: NixOS 模块存在 Bug#

服务器的系统是相当灵车的 NixOS,因此很自然就会想到是不是 unstable 分支的模块又炸了。NixOS 模块配置如下:

boot.swraid = {
  enable = true;
  # 以下填入 sudo mdadm --detail --scan 的结果
  mdadmConf = ''
    ARRAY /dev/md0 metadata=1.2 UUID=aaaaaaaa:bbbbbbbb:cccccccc:dddddddd
  '';
};
fileSystems."/mnt/raid0" = {
  device = "/dev/md0";
  fsType = "ext4";
  options = [
    "defaults"
    "noatime"
  ];
};

当即想到是不是启动时序问题,RAID 设备在 Stage 1 - initrd 阶段未被加载。又因为老觉得 mdadm 是由 systemd 启动的(这是我当时的误解!),于是尝试改变 initrd 为由 systemd 加载:boot.initrd.systemd.enable = true;

非常幸运……问题没有解决。nixpkgs 仓库里也没有相应的 Issue,按理来说如果确实是 Bug 会有人报告的,看起来不太像是 NixOS 的 Bug。

怀疑 2: 硬盘坏了#

穷鬼就是穷鬼,捡来的硬盘已经通电几万小时了。刚拿到手我就怕它坏了,呜呜呜呜呜呜呜,现在终于坏掉了……吗?

执行以下命令扫描硬盘上 RAID 阵列的元数据:

sudo mdadm --detail --scan
sudo mdadm --assemble --scan # 尝试根据硬盘上的元数据组装阵列

没有结果,说明硬盘上 RAID 的元数据已经被摧毁(其实不是,后面有反转!)。

呜呜呜,它真的坏了……个鬼。在重新创建阵列并格式化后:

sudo mdadm --create --verbose /dev/md0 --level=0 --raid-devices=2 /dev/sda /dev/sdc
sudo mkfs.ext4 /dev/md0

新的阵列可以正常挂载并使用,sudo mdadm --detail --scan 命令也有结果。但是在重启后,它又不见了,症状和上面一模一样。说明不是硬盘坏掉的问题。

同病相怜相见恨晚伯牙遇子期#

充满怒火地在网上搜索,见到了这样一篇帖子,症状和我的一样:记一次采坑经历, mdadm 创建 raid0,重启后自动消失

询问 Gemini 后,它告诉我:

结论与解决方案#

结论#

出现这个问题的原因是:磁盘签名冲突。

Linux 内核和 systemd 会优先识别常见的磁盘结构,比如 GPT(GUID 分区表)和 MBR(主引导记录)。

  • 当系统检测到带有 GPT 签名的磁盘时,会立即将其视为一个已经分区的设备。
  • mdadm 工具和 mdraid 内核模块则被设计为在整个磁盘或某个分区上寻找它们的超级块(superblock)。
  • 如果一个磁盘带有 GPT 头部,它就已经被识别为一个分区的设备。mdraid 内核模块可能因此无法将其识别为一块用于 RAID 的、未被分区的“裸磁盘”(raw disk),从而导致阵列无法组装。

简而言之,就是残留在磁盘上的 GPT 分区数据“欺骗”了系统,让它看到了一个分区表,而不是一块可以用于 RAID 的原始磁盘。

解决方案#

1. 擦除分区表信息#

如果磁盘已经被用于 RAID 阵列,则擦除超级块:

sudo mdadm --zero-superblock --force /dev/sda
sudo mdadm --zero-superblock --force /dev/sdc

sgdisk (gptfdisk 包) 清空整个磁盘,包括分区表信息:

sudo sgdisk --zap-all /dev/sda
sudo sgdisk --zap-all /dev/sdc

以防万一,再次擦除储存分区信息的扇区:

sudo dd if=/dev/zero of=/dev/sda bs=1M count=100
sudo dd if=/dev/zero of=/dev/sdc bs=1M count=100

sudo fdisk -l 检验是否成功。当磁盘信息里不显示 磁盘标签类型:gpt 时,擦除已经成功。

2. 正常创建 RAID 阵列#

擦除成功后,再次创建 RAID 阵列。

sudo mdadm --create --verbose /dev/md0 --level=0 --raid-devices=2 /dev/sda /dev/sdc
sudo mkfs.ext4 /dev/md0

此时再重启,RAID 阵列应该能正常挂载。用 lsblk 检测,TYPE 应为 raid0 而非 part

结语#

浪费了 3 个小时。

附录 1:NixOS 下正确挂载 RAID 阵列的方式#

boot.swraid = {
  enable = true;
  # 以下填入 sudo mdadm --detail --scan 的结果
  mdadmConf = ''
    ARRAY /dev/md0 metadata=1.2 UUID=aaaaaaaa:bbbbbbbb:cccccccc:dddddddd
  '';
};
fileSystems."/mnt/raid0" = {
  device = "/dev/md0";
  fsType = "ext4";
  options = [
    "defaults"
    "noatime"
  ];
};

附录 2:NixOS 下设置硬盘自动休眠的方式#

environment.systemPackages = [ pkgs.hd-idle ];
systemd.services.hd-idle = {
  serviceConfig = {
    Type = "simple";
    User = "root";
    ExecStart =
      let
        mkDisk = label: timeInMinutes: "-a /dev/${label} -i ${toString (timeInMinutes * 60)}";
        disks = lib.concatStringsSep " " [
          (mkDisk "sda" 10)
          (mkDisk "sdb" 10)
          (mkDisk "sdd" 10)
        ];
        extraOptions = lib.concatStringsSep " " [
          "-l /tmp/hd-idle.log"
          "-d" # Debug
          "-I" # Ignores spin down detection. Spins down the disk even it's already been.
        ];
      in
      ''${lib.getExe pkgs.hd-idle} ${extraOptions} -i 0 ${disks}'';
  };
  wantedBy = [ "multi-user.target" ];
};
记一次由于 GPT 分区表冲突导致的重启后 RAID 设备消失,附 NixOS 下 RAID 挂载和磁盘休眠的配置
https://blog.lzc256.com/posts/raid-device-corrupted-caused-by-gpt-partition-table-conflict/
作者
落雨宸
发布于
2025-09-08
许可协议
CC BY-NC-SA 4.0


Loading Comment Component...