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 设备 编号

md 设备的编号

md 设备 编号

设备

0

md0

1

md1

2

md2

3

md3

4

md4

raid 级别

RAID 阵列的级别

raid 级别

级别

-1

线性模式

0

条带模式

其他模式仅在持久超级块的情况下支持

大小 因子

(仅限 raid-0 和 raid-1)

将块大小设置为 4k << n。

故障 级别

完全忽略

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 阵列既是脏的又是降级的,则可能存在无法检测到的数据损坏。这是因为它是 脏的 意味着奇偶校验不可信,并且它是降级的事实意味着某些数据块丢失并且无法可靠地重建(由于没有奇偶校验)。

因此,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 虚拟设备关联来 组装 它。一旦完全组装好,就可以访问它。

应该由用户空间工具创建阵列。这将向所有设备写入超级块。它通常会将阵列标记为 不干净,或者某些设备丢失,以便内核 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==0 并且 raid_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 设备都包含

级别

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

raid_disks

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

chunk_size

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

layout

特定级别的阵列的 layout。这只是一个数字,由不同的级别以不同的方式解释。可以在组装阵列时写入。

array_size

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

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

reshape_position

这可以是 none 或阵列设备中的一个扇区号,表示 reshape 的进度。如果设置了此值,则上述三个属性(raid_disks、chunk_size、layout)可能具有 2 个值,一个旧值和一个新值。如果这些值不同,则读取属性将返回

new (old)

写入将影响 new 值,而保持 old 值不变。

component_size

对于具有数据冗余的阵列(即,不是 raid0、linear、faulty、multipath),所有组件的大小必须相同 - 或者至少必须存在一个它们都提供空间的大小。这是阵列几何形状的关键部分。它以扇区为单位进行测量,并且可以从此处读取。如果特性支持(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。这被称为 safe_modecertain period 由此文件控制,该文件将该周期存储为秒数。默认值为 200 毫秒 (0.200)。写入值 0 将禁用安全模式。

array_state

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

选择/轮询在此文件上起作用。除了 Active_idle 和 active 之间的更改(这可能是频繁的并且不是很重要)之外,所有更改都会被通知。如果元数据由外部管理,则会报告 active->active_idle。

clear

没有设备、没有大小、没有级别

写入等效于 STOP_ARRAY ioctl

inactive

可能有一些设置,但阵列未激活,所有 IO 操作都会导致错误

写入时,不会拆除阵列,只是停止它

suspended(尚不支持)

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

如果接受,则写入此项将阻止,直到阵列处于静止状态

readonly

不会发生重新同步。不会写入超级块。

写入请求失败

read-auto

类似只读,但在写入请求时表现得像 clean

clean

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

写入非活动阵列时,启动时不进行重新同步

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

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

active

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

write-pending

clean,但写入被阻止,等待写入 active

active-idle

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

bitmap/location

这表示阵列的写入意图位图的存储位置。

它可以是 nonefile[+-]N 之一。file 稍后可能会扩展为 file:/file/name[+-]N 表示元数据开始的扇区数。

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

bitmap/chunksize

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

bitmap/time_base

在查找要清除的位图中的位之间的时间(以秒为单位)。在当前实现中,在知道所有覆盖的块都处于同步状态后,将在 2 到 3 倍 time_base 之间清除一个位。

bitmap/backlog

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

bitmap/metadata

这可以是 internalexternal

internal

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

external

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

bitmap/can_clear

这可以是 truefalse。如果 true,则当认为对应的块处于同步状态时,将清除位图中的位。如果 false,则永远不会清除位。如果在降级的阵列上发生写入,或者在写入期间阵列变为降级状态,则会自动将其设置为 false。当元数据由外部管理时,一旦阵列变为非降级状态,并且此事实已记录在元数据中,则应将其设置为 true。

consistency_policy

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

none

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

resync

在不正常关机后启动阵列时,将执行完全重新同步,并重新生成所有冗余。

bitmap

由写入意图位图辅助的重新同步。

journal

对于 raid4/5/6,使用日志设备来记录事务并在不正常关机后重播。

ppl

仅对于 raid5,使用部分奇偶校验日志来关闭写入漏洞并消除重新同步。

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

uuid

这表示阵列的 UUID,格式如下:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

当组件设备添加到 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

这给出了所有已知坏块的列表,形式为起始地址和长度(分别为扇区)。如果输出太大而无法容纳在一页中,则会将其截断。将 sector length 写入此文件会添加新的已确认(即安全记录到磁盘)的坏块。

unacknowledged_bad_blocks

这给出了已知但尚未保存到磁盘的坏块列表,形式与 bad_blocks 相同。如果输出太大而无法容纳在一页中,则会将其截断。写入此文件会添加未确认的坏块。这主要用于测试。

ppl_sector, ppl_size

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

活动的 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 将停止活动的重新同步/恢复等。不能保证不会再次自动启动另一个重新同步/恢复,但需要一些事件来触发此操作。

如果使用 idle 停止了相应的操作,则可以使用 resyncrecovery 重新启动。

如果当前状态为 idle,则 checkrepair 将启动相应的进程。

此文件响应 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,则使用系统范围的值。如果写入以千字节/秒为单位的值,则使用它。

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

sync_completed

这显示了当前 sync_action 完成的扇区数,后跟可能需要处理的总扇区数。这两个数字用 / 分隔,从而有效地显示一个值,即完成过程的分数。

当重新同步完成时,当它达到当前 sync_max(如下)时以及可能在其他时间,对此属性进行 select 将返回。

sync_speed

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

suspend_lo, suspend_hi

这两个值以扇区数给出,表示阵列中将阻止 IO 的范围。目前仅支持 raid4/5/6。

sync_min, sync_max

这两个值以扇区数为单位给出,表示数组中 check/repair 将要操作的范围。必须是 chunk_size 的倍数。当达到 sync_max 时,它将暂停,而不是完成。你可以使用 selectpollsync_completed 上等待该值达到 sync_max。然后你可以增加 sync_max,或者可以向 sync_action 写入 idle

sync_maxmax 值实际上禁用了该限制。当重新同步处于活动状态时,该值只能增加,永远不能减少。sync_min 的最小值为 0

每个活动的 md 设备也可能具有特定于管理它的个性模块的属性。这些属性特定于模块的实现,如果实现发生更改,则可能会发生重大变化。

目前包括:

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-throuth”和“write-back”。默认值为“write-through”。

ppl_write_hint

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