From ccb185f0ea2a451ad7429b49f6fd172ccb0375f9 Mon Sep 17 00:00:00 2001 From: Sueun Cho Date: Fri, 10 Jul 2026 10:35:29 -0500 Subject: [PATCH] fix(mdstat): parse (W), (J) and (R) component device flags componentDeviceRE only captured ([SF]+), so the WriteMostly, Journal and Replacement fields read from match[3] were always false, and a flag following another one was dropped entirely - for sde1[4](W)(F) the group matched nothing, losing Faulty as well. The kernel prints each flag as its own parenthesis group, so capture a run of them. Signed-off-by: Sueun Cho --- mdstat.go | 2 +- mdstat_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/mdstat.go b/mdstat.go index d66eeda8..90410179 100644 --- a/mdstat.go +++ b/mdstat.go @@ -27,7 +27,7 @@ var ( recoveryLinePctRE = regexp.MustCompile(`= (.+)%`) recoveryLineFinishRE = regexp.MustCompile(`finish=(.+)min`) recoveryLineSpeedRE = regexp.MustCompile(`speed=(.+)[A-Z]`) - componentDeviceRE = regexp.MustCompile(`(.*)\[(\d+)\](\([SF]+\))?`) + componentDeviceRE = regexp.MustCompile(`(.*)\[(\d+)\]((?:\([FJRSW]\))+)?`) personalitiesPrefix = "Personalities : " ) diff --git a/mdstat_test.go b/mdstat_test.go index 4d94f93c..0a4bf539 100644 --- a/mdstat_test.go +++ b/mdstat_test.go @@ -369,3 +369,31 @@ md127 : active raid1 sdi2[0] sdj2[X] } } } +func TestEvalComponentDevicesFlags(t *testing.T) { + // Flags as printed by the kernel, one per parenthesis group: + // https://github.com/torvalds/linux/blob/7ec462100ef9142344ddbf86f2c3008b97acddbe/drivers/md/md.c#L8376-L8392 + devices, err := evalComponentDevices([]string{ + "sda1[0](F)", + "sdb1[1](W)", + "sdc1[2](J)", + "sdd1[3](R)", + "sde1[4](W)(F)", + "sdg1[6](S)", + "sdf1[5]", + }) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + want := []MDStatComponent{ + {Name: "sda1", DescriptorIndex: 0, Faulty: true}, + {Name: "sdb1", DescriptorIndex: 1, WriteMostly: true}, + {Name: "sdc1", DescriptorIndex: 2, Journal: true}, + {Name: "sdd1", DescriptorIndex: 3, Replacement: true}, + {Name: "sde1", DescriptorIndex: 4, WriteMostly: true, Faulty: true}, + {Name: "sdg1", DescriptorIndex: 6, Spare: true}, + {Name: "sdf1", DescriptorIndex: 5}, + } + if diff := cmp.Diff(want, devices); diff != "" { + t.Errorf("unexpected component devices (-want +got):\n%s", diff) + } +}