RAID 阵列

引导时组装 RAID 阵列

管理 md 设备的工具可以在此处找到:

https://linuxkernel.org.cn/pub/linux/utils/raid/

您可以使用以下内核命令行引导您的 md 设备

适用于不带持久超级块的旧式 raid 阵列

md=<md device no.>,<raid level>,<chunk size factor>,<fault level>,dev0,dev1,...,devn

适用于带有持久超级块的 raid 阵列

md=<md device no.>,dev0,dev1,...,devn

或者,组装一个可分区的阵列

md=d<md device no.>,dev0,dev1,...,devn

md device no.

md 设备的编号

md 设备编号

device

0

md0

1

md1

2

md2

3

md3

4

md4

raid level

RAID 阵列的级别

raid 级别

level

-1

线性模式 (linear)

0

带区模式 (striped)

其他模式仅支持持久超级块

chunk size factor

(仅适用于 raid-0 和 raid-1)

设置块大小(chunk size)为 4k << n。

fault level

完全忽略

dev0devn

例如 /dev/hda1, /dev/hdc1, /dev/sda1, /dev/sdb1

一个可能的 loadlin 命令行(Harald Hoyer <HarryH@Royal.Net>)如下所示

e:\loadlin\loadlin e:\zimage root=/dev/md0 md=0,0,4,0,/dev/hdb2,/dev/hdc3 ro

引导时 RAID 阵列的自动检测

当 md 被编译进内核(而非作为模块)时,类型为 0xfd 的分区将被扫描并自动组装成 RAID 阵列。可以使用内核参数 raid=noautodetect 禁用此自动检测。从内核 2.6.9 开始,只有带有 0 型超级块的驱动器可以在引导时自动检测并运行。

内核参数 raid=partitionable (或 raid=part) 意味着所有自动检测到的阵列都作为可分区阵列组装。

引导时组装降级/脏阵列

如果 raid5 或 raid6 阵列既是脏的(dirty)又是降级的(degraded),它可能会发生无法检测到的数据损坏。这是因为 意味着校验数据不可信,而 降级 意味着某些数据块丢失且无法可靠重建(由于没有校验数据)。

由于这个原因,md 通常会拒绝启动此类阵列。这需要系统管理员采取行动,在存在损坏可能的情况下显式启动阵列。通常通过以下方式完成

mdadm --assemble --force ....

如果阵列包含根文件系统,此选项实际上不可用。为了支持从这种阵列引导,md 支持一个模块参数 start_dirty_degraded,当设置为 1 时,它将绕过检查并允许启动脏降级阵列。

因此,要使用脏降级 raid 5 或 6 的根文件系统进行引导,请使用

md-mod.start_dirty_degraded=1

超级块格式

md 驱动程序支持多种不同的超级块格式。目前支持超级块格式 0.90.0 以及在 2.5 开发系列中引入的 md-1 格式。

内核会自动检测正在使用的超级块格式。

由于历史原因,超级块格式 0 的处理方式与其他格式不同——它是最初的超级块格式。

通用规则 - 适用于所有超级块格式

通过向所有设备写入相应的超级块来 创建 阵列。

通过将这些设备中的每一个与特定的 md 虚拟设备关联来 组装 阵列。一旦完全组装,即可对其进行访问。

阵列应由用户空间工具创建。这将向所有设备写入超级块。它通常会将阵列标记为 不洁(unclean),或者某些设备缺失,以便内核 md 驱动程序可以创建适当的冗余(在 raid 1 中复制,在 raid 4/5 中进行校验计算)。

组装阵列时,首先使用 SET_ARRAY_INFO ioctl 进行初始化。这主要包含主版本号和次版本号。主版本号选择要使用的超级块格式。次版本号可能用于微调格式的处理,例如建议在每个设备的哪个位置寻找超级块。

然后使用 ADD_NEW_DISK ioctl 添加每个设备。这主要提供识别要添加设备的主设备号和次设备号。

使用 RUN_ARRAY ioctl 启动阵列。

启动后,可以添加新设备。应在其中写入适当的超级块,然后通过 ADD_NEW_DISK 传入。

故障或尚未激活的设备可以使用 HOT_REMOVE_DISK 从阵列中卸载。

适用于 0 格式超级块阵列以及无超级块阵列(非持久)的特定规则

可以通过在 SET_ARRAY_INFO ioctl 中描述阵列(级别、块大小等)来 创建 阵列。这必须满足 major_version==0raid_disks != 0

然后可以使用 ADD_NEW_DISK 添加未初始化的设备。传递给 ADD_NEW_DISK 的结构体必须指定设备的状态及其在阵列中的角色。

一旦使用 RUN_ARRAY 启动,就可以使用 HOT_ADD_DISK 添加未初始化的备用盘。

sysfs 中的 md 设备

md 设备在 sysfs (/sys) 中显示为常规块设备,例如:

/sys/block/md0

每个 md 设备都包含一个名为 md 的子目录,其中包含有关该设备的进一步 md 特定信息。

所有 md 设备都包含:

level

一个指示 raid level(RAID 级别)的文本文件。例如 raid0, raid1, raid5, linear, multipath, faulty。如果尚未设置 raid 级别(阵列仍在组装中),该值将反映已写入其中的内容,可能是一个类似上述的名称,也可能是一个数字,如 0, 5 等。

raid_disks

一个包含简单数字的文本文件,指示功能完备的阵列中的设备数量。如果尚不清楚,该文件将为空。如果阵列正在调整大小,这将包含新的设备数量。某些 raid 级别允许在阵列处于活动状态时设置此值,这将会重新配置阵列。否则,只能在组装阵列时设置。如果更改此属性会减小阵列大小,则不允许更改。要减少例如 raid5 中的驱动器数量,必须首先通过设置 array_size 属性来减小阵列大小。

chunk_size

这是块(chunk)的大小(以字节为单位),仅与涉及带区化的 raid 级别(0,4,5,6,10)相关。阵列的地址空间在概念上被划分为块,连续的块被条带化到相邻的设备上。大小应至少为 PAGE_SIZE (4k) 且应为 2 的幂。这只能在组装阵列时设置。

layout

阵列针对特定级别的 布局。这仅仅是一个数字,由不同的级别进行不同的解释。它可以在组装阵列时写入。

array_size

这可用于人为地将阵列中的可用空间限制为小于组合设备上实际可用的空间。写入一个小于可用大小的数字(以 KB 为单位)将设置该大小。阵列的任何重新配置(例如添加设备)都不会导致大小改变。写入单词 default 将使阵列的有效大小恢复为基于 levelchunk_sizecomponent_size 实际可用的任何大小。

这可用于在减少 raid4/5/6 中的设备数量之前减小阵列大小,或用于支持强制执行此类裁剪的外部元数据格式。

logical_block_size

配置阵列的逻辑块大小(以字节为单位)。此属性仅支持 1.x 元数据。在启动阵列之前写入该值。最终阵列的 LBS 使用此配置与所有组合设备的 LBS 之间的最大值。请注意,在 RAID 支持 folio 之前,LBS 不能超过 PAGE_SIZE。警告:在新内核上创建的阵列由于填充检查而无法在旧内核上组装,将模块参数 ‘check_new_feature’ 设置为 false 可以绕过,但可能会发生数据丢失。

reshape_position

这可以是 none 或阵列设备内的扇区号,指示 重塑(reshape) 的进度。如果设置了此项,则上述三个属性(raid_disks, chunk_size, layout)可能有 2 个值:旧值和新值。如果这些值不同,读取该属性会返回:

new (old)

并且写入将影响 值,保持 值不变。

component_size

对于具有数据冗余的阵列(即非 raid0、linear、faulty、multipath),所有组件必须具有相同的大小——或者至少必须有一个它们都能提供空间的大小。这是阵列几何结构的关键部分。它以扇区为单位,并可从此处读取。如果 personality 支持(raid1, raid5, raid6)且组件驱动器足够大,写入此值可能会调整阵列的大小。

metadata_version

这指示用于记录阵列元数据的格式。它可以是 0.90(传统格式)、1.0、1.1、1.2(位置不同的较新格式)或 none,表示内核根本不管理元数据。或者它可以是 external: 后跟一个由用户空间设置的字符串。这表示元数据由用户空间程序管理。任何需要元数据更新的设备故障或其他事件都将导致阵列活动挂起,直到事件得到确认。

resync_start

应开始重新同步的点。如果不需要重新同步,这将是一个非常大的数字(或自 2.6.30-rc1 以来为 none)。在创建阵列时,它默认为 0,但将阵列作为 clean(干净)启动会将其设置得大得多。

new_dev

此文件可写但不可读。写入的值应为 major:minor 格式的块设备号,例如 8:0。如果该设备可用,这将导致该设备附加到阵列。然后它将出现在 md/dev-XXX(取决于设备名称),并可以进行进一步配置。

safe_mode_delay

当 md 阵列在一定时间内没有收到写请求时,它将被标记为 干净(clean)。当另一个写请求到达时,在写入开始之前阵列被标记为 脏(dirty)。这被称为 安全模式一定时间 由该文件控制,该文件以秒数存储该时间段。默认值为 200 毫秒 (0.200)。写入 0 将禁用安全模式。

array_state

此文件包含一个描述阵列当前状态的单词。在许多情况下,可以通过写入所需状态的单词来设置状态,但某些状态无法显式设置,且某些状态转换是不允许的。

Select/poll 适用于此文件。除 Active_idle 和 active 之间的更改(更改可能频繁且不太重要)外,所有更改都会得到通知。如果元数据是外部管理的,则会报告 active->active_idle。

清除

无设备,无容量,无级别

写入等同于 STOP_ARRAY ioctl

inactive

可能有某些设置,但阵列未激活,所有 IO 均导致错误

写入时,不会销毁阵列,只是停止它

suspended (尚未支持)

所有 IO 请求都将阻塞。可以重新配置阵列。

如果接受写入此项,将阻塞直到阵列进入静态(quiescent)

readonly

无法进行同步。不写入超级块。

写请求失败

read-auto

类似于 readonly,但在收到写请求时行为类似于 clean

clean

没有挂起的写入,但处于活动状态。

当写入非活动阵列时,启动而不进行同步

如果写请求到达且元数据已知,则标记为 dirty 并切换到 active。如果未知,则阻塞并切换到 write-pending。

如果写入有挂起写入的活动阵列,则会失败。

active

完全活动:IO 和重新同步可能正在发生。当写入非活动阵列时,启动并进行同步

write-pending

干净,但写入被阻塞等待写入 active

active-idle

类似于 active,但有一段时间(safe_mode_delay)没有看到写入。

consistency_policy

这指示阵列如何在意外关闭的情况下保持一致性。它可以是:

阵列没有冗余信息,例如 raid0, linear。

resync

在不洁关闭后启动阵列时,将执行全量重新同步并重新生成所有冗余。

bitmap

由写意图位图(write-intent bitmap)辅助的同步。

journal

对于 raid4/5/6,日志设备用于记录事务并在不洁关闭后重放。

ppl

仅针对 raid5,部分校验日志(Partial Parity Log)用于关闭写漏洞并消除重新同步。

写入此文件时接受的值为 pplresync,用于启用和禁用 PPL。

uuid

这以以下格式指示阵列的 UUID:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

bitmap_type

[RW] 读取时,此文件将显示此阵列当前和可用的位图。当前活动的位图将包含在 [] 括号中。向此文件写入位图名称或 ID 将把此阵列的控制切换到该新位图。注意,禁止为已创建的阵列写入新位图。

无位图

bitmap

默认的内部位图

llbitmap

无锁(lockless)内部位图

如果 bitmap_type 不是 none,则在 md 设备 KOBJ_CHANGE 事件之后,将创建额外的位图属性 bitmap/xxx 或 llbitmap/xxx。

如果 bitmap_type 是 bitmap,则 md 设备还将包含:

bitmap/location

这指示阵列的写意图位图存储在何处。

它可以是 none, file[+-]Nfile 以后可能会扩展为 file:/file/name[+-]N 表示距离元数据开始的扇区数。

这在所有设备上都有备份。对于具有外部管理元数据的阵列,偏移量是从设备的起始位置开始计算的。

bitmap/chunksize

将由单个位表示的块的大小(以字节为单位)。对于 RAID456,它是单个设备的一部分。对于 RAID10,它是阵列的一部分。对于 RAID1,两者皆是(结果相同)。

bitmap/time_base

在寻找位图中的位以进行清除之间的时间(以秒为单位)。在当前的实现中,在已知所有覆盖的块都已同步后,位将在 time_base 的 2 到 3 倍时间内被清除。

bitmap/backlog

当 write-mostly 设备在 RAID1 中处于活动状态时,对这些设备的写请求在后台进行——文件系统(或设备的其他使用者)不必等待它们。backlog 设置并发后台写入次数的限制。如果超过此限制,新的写入将变为同步。

bitmap/metadata

这可以是 internalexternal

internal

是默认值,表示位图的元数据存储在分配空间的前 256 字节中,并由 md 模块管理。

external

表示位图元数据在内核之外进行管理(即由某些用户空间程序管理)

bitmap/can_clear

这可以是 truefalse。如果为 true,则当相应的块被认为已同步时,位图中的位将被清除。如果为 false,位将永远不会被清除。如果阵列降级或在写入过程中阵列变为降级,此值将自动设置为 false。当元数据在外部管理时,一旦阵列不再降级且此事实已记录在元数据中,应将其设置为 true。

如果 bitmap_type 是 llbitmap,则 md 设备还将包含:

llbitmap/bits

只读,显示位图位的状态,以及每个值的数量。

llbitmap/metadata

只读,显示位图元数据,包括 chunksize, chunkshift, chunks, offset 和 daemon_sleep。

llbitmap/daemon_sleep

读写,触发守护进程函数以清除脏位的间隔时间(秒)。

llbitmap/barrier_idle

读写,页面屏障闲置的时间(秒),表示页面中的脏位将被清除。

随着组件设备被添加到 md 阵列,它们会作为新目录出现在 md 目录中,命名如下:

dev-XXX

其中 XXX 是内核已知的设备名称,例如 hdb1。每个目录包含:

block

指向 /sys/block 中块设备的符号链接,例如:

/sys/block/md0/md/dev-hdb1/block -> ../../../../block/hdb/hdb1
super

包含从该设备读取或写入该设备的超级块映像的文件。

state

记录阵列中设备当前状态的文件,可以是以逗号分隔的列表,包含以下内容:

faulty

设备由于检测到故障而被踢出活动使用,或者它有未确认的坏块

in_sync

设备是阵列中完全同步的成员

writemostly

除非没有其他选择,否则设备将只受制于读请求。

这仅适用于 raid1 阵列。

blocked

设备已发生故障,且故障尚未被元数据处理器确认。

如果该设备不是故障设备,则本应写入该设备的写入将被阻塞。

spare

设备正在工作,但不是正式成员。

这包括正在进行恢复操作的备用盘

write_error

设备曾出现过写错误。

want_replacement

设备(大部分)正常工作,但由于错误或用户请求,可能需要更换。

replacement

设备是具有相同 raid_disk 的另一个活动设备的替代品。

此列表将来可能会增加。

此文件是可写的。

写入 faulty 模拟设备上的故障。

写入 remove 将设备从阵列中移除。

写入 writemostly 设置 writemostly 标志。

写入 -writemostly 清除 writemostly 标志。

写入 blocked 设置 blocked 标志。

写入 -blocked 清除 blocked 标志,允许完成写入,并可能模拟一个错误。

写入 in_sync 设置 in_sync 标志。

写入 write_error 设置 writeerrorseen 标志。

写入 -write_error 清除 writeerrorseen 标志。

允许随时写入 want_replacement,但不能写入替代设备或备用盘。它会设置该标志。

允许随时写入 -want_replacement。它会清除该标志。

仅允许在启动阵列之前写入 replacement-replacement。它会设置或清除该标志。

此文件响应 select/poll。对 faultyblocked 的任何更改都会引起一个事件。

errors

在该设备上检测到的读错误的近似计数,但未导致设备被逐出阵列(要么是因为它们已被纠正,要么是因为它们发生在阵列只读期间)。使用第 1 版元数据时,此值在阵列重启后仍然保持。

可以在组装阵列时写入此值,从而为元数据由用户空间管理的阵列提供持续计数。

slot

这给出了设备在阵列中的角色。如果设备在阵列中不活跃(即是备用盘或已发生故障),它将为 none;或者是一个小于阵列 raid_disks 数量的整数,指示它当前填充的位置。这只能在组装阵列时设置。设置此项的设备被假定为工作正常的。

offset

这给出了设备中存储阵列数据的位置(从开始处计算的扇区数)。此偏移量之前的任何部分都不会被触及,除非它用于存储元数据(格式 1.1 和 1.2)。

size

偏移量之后可用于存储数据的设备量。通常与 component_size 相同。这可以在组装阵列时写入。如果写入的值小于当前的 component_size,它将被拒绝。

recovery_start

当设备不是 in_sync 时,此项记录从设备起始位置开始已知正确的扇区数。这通常为零,但在恢复操作期间它会稳步增加,如果恢复中断,恢复此值可以使恢复避免重复前面的块。使用 v1.x 元数据,此值会自动保存和恢复。

只要设备不是阵列的活动成员,无论是在激活阵列之前还是在设置 slot(插槽)之前,都可以设置此项。

将其设置为 none 等同于设置 in_sync。设置为任何其他值也会清除 in_sync 标志。

bad_blocks

这以起始地址和长度(分别为扇区数)的形式给出了所有已知坏块的列表。如果输出太大而无法放入一个页面,它将被截断。向此文件写入 扇区号 长度 会添加新的已确认(即已安全记录到磁盘)坏块。

unacknowledged_bad_blocks

这以 bad_blocks 的相同形式给出了已知但尚未保存到磁盘的坏块列表。如果输出太大而无法放入一个页面,它将被截断。向此文件写入内容会添加坏块但不确认它们。这主要用于测试。

ppl_sector, ppl_size

此设备上用于部分校验日志(Partial Parity Log)的空间的位置和大小(以扇区为单位)。

活动的 md 设备还将包含阵列中每个活动设备的条目。这些被命名为:

rdNN

其中 NN 是阵列中的位置,从 0 开始。因此,对于 3 驱动器阵列,将会有 rd0, rd1, rd2。这些是到相应 dev-XXX 条目的符号链接。例如:

cat /sys/block/md*/md/rd*/state

每行都会显示 in_sync

支持数据冗余的级别(1,4,5,6,10)的活动 md 设备还具有:

sync_action

一个可用于监控和控制重建过程的文本文件。它包含一个单词,可以是以下之一:

resync

在不洁关闭或创建后,正在重新计算冗余

recover

正在构建热备用盘以替换故障/缺失的设备

idle

什么都没发生

check

已请求全量冗余检查且正在进行。这将读取所有块并进行检查。对于某些 raid 级别,也可能发生修复。

repair

全量检查并修复正在进行。这类似于 resync,但是由用户请求的,并且不使用写意图位图来优化过程。

此文件是可写的,且可以读取的每个字符串对于写入也都有意义。

idle 将停止活动的 resync/recovery 等。不能保证另一个 resync/recovery 不会自动再次启动,尽管需要某些事件来触发它。

resyncrecovery 可用于重启由于 idle 停止的相应操作。

如果当前状态为 idlecheckrepair 将启动相应的进程。

此文件响应 select/poll。值的任何重要更改都会触发轮询事件。有时,如果似乎需要恢复但无法实现,值会短暂变为 recover。在这种情况下,不通知向 recover 的转换,但通知从其离开的转换。

degraded

这包含阵列降级的设备数量。因此,最佳阵列将显示 0。单个故障/缺失的驱动器将显示 1,以此类推。

此文件响应 select/poll,缺失设备数量的任何增加或减少都会触发一个事件。

mismatch_count

在执行 checkrepair,以及执行 resync 时,md 将计算发现的错误数量。mismatch_cnt 中的计数是已重写或(对于 check)本应重写的扇区数。由于大多数 raid 级别是以页面而非扇区为单位工作,这可能比实际错误数量大,因数是一个页面中的扇区数。

bitmap_set_bits

如果阵列有写意图位图,则写入此属性可以设置位图中的位,指示同步需要检查相应的块。可以写入单个数字或起止对。多个数字可以用空格分隔。

请注意,这些数字是 位(bit) 编号,而不是 块(block) 编号。它们应按 bitmap_chunksize 进行缩放。

sync_speed_min, sync_speed_max

这些类似于 /proc/sys/dev/raid/speed_limit_{min,max},但它们仅适用于特定阵列。

如果没有给这些文件写入任何值,或者写入了单词 system,则使用系统范围的值。如果写入一个以 KiB/s 为单位的值,则使用该值。

读取文件时,它们会显示当前活动的值,后跟 (local)(system),取决于它是本地设置的值还是系统范围的值。

sync_completed

这显示了当前 sync_action 已完成的扇区数,后跟可能需要处理的总扇区数。这两个数字由 / 分隔,实际上显示为一个值,即已完成进度的比例。

在此属性上的 select 将在同步完成、达到当前的 sync_max(见下文)以及可能在其他时间返回。

sync_speed

这显示了当前 sync_action 的实际当前速度,单位为 KiB/sec。它是过去 30 秒内的平均值。

suspend_lo, suspend_hi

这两个值以扇区数给出,指示阵列中将阻塞 IO 的范围。目前仅针对 raid4/5/6 提供支持。

sync_min, sync_max

这两个值以扇区数给出,指示 check/repair 操作的范围。必须是 chunk_size 的倍数。当达到 sync_max 时,它将暂停而不是完成。您可以在 sync_completed 上使用 selectpoll 来等待该数字达到 sync_max。然后您可以增加 sync_max,或者向 sync_action 写入 idle

sync_max 的值为 max 有效地禁用了限制。当同步处于活动状态时,该值只能增加,不能减少。0sync_min 的最小值。

每个活动的 md 设备还可能具有管理它的 personality 模块所特有的属性。这些是模块实现的特有属性,如果实现发生更改,它们可能会发生实质性变化。

目前包括:

stripe_cache_size (目前仅限 raid5)

带区缓存中的条目数。这是可写的,但有上限和下限(32768, 17)。默认值为 256。

strip_cache_active (目前仅限 raid5)

带区缓存中的活动条目数

preread_bypass_threshold (目前仅限 raid5)

需要预读的带区被不需要预读的带区绕过的次数。为了公平性,默认值为 1。将其设置为 0 会禁用绕过核算,并要求预读带区等待,直到所有全宽度带区写入完成。有效值为 0 到 stripe_cache_size。

journal_mode (目前仅限 raid5)

raid5 的缓存模式。raid5 可以包含一个额外的磁盘用于缓存。模式可以是 “write-through” 或 “write-back”。默认值为 “write-through”。

ppl_write_hint

为每个 PPL 写请求设置的 NVMe 流 ID。