mirror of
https://github.com/flatcar/scripts.git
synced 2026-05-14 00:26:13 +02:00
sys-apps/ignition: Patch to address partitioning race conditions
Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
This commit is contained in:
parent
c580830d40
commit
3ff790c37f
@ -0,0 +1,108 @@
|
||||
From 31f898a9eef2fdf83683b0f5d9551d45e669223d Mon Sep 17 00:00:00 2001
|
||||
From: James Le Cuirot <jlecuirot@microsoft.com>
|
||||
Date: Mon, 11 May 2026 12:25:38 +0100
|
||||
Subject: [PATCH 1/2] stages/disks: Make getRealStartAndSize return a map like
|
||||
it says it does
|
||||
|
||||
This is useful for the code I'm about to add. Use int rather than uint64
|
||||
because that's what sgdisk.Partition.Number uses. That should be more
|
||||
than big enough!
|
||||
|
||||
Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
|
||||
---
|
||||
internal/exec/stages/disks/partitions.go | 24 ++++++++++++------------
|
||||
1 file changed, 12 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/internal/exec/stages/disks/partitions.go b/internal/exec/stages/disks/partitions.go
|
||||
index 9a7ae9ca..469ba77f 100644
|
||||
--- a/internal/exec/stages/disks/partitions.go
|
||||
+++ b/internal/exec/stages/disks/partitions.go
|
||||
@@ -133,7 +133,7 @@ func convertMiBToSectors(mib *int, sectorSize int) *int64 {
|
||||
// getRealStartAndSize returns a map of partition numbers to a struct that contains what their real start
|
||||
// and end sector should be. It runs sgdisk --pretend to determine what the partitions would look like if
|
||||
// everything specified were to be (re)created.
|
||||
-func (s stage) getRealStartAndSize(dev types.Disk, devAlias string, diskInfo util.DiskInfo) ([]sgdisk.Partition, error) {
|
||||
+func (s stage) getRealStartAndSize(dev types.Disk, devAlias string, diskInfo util.DiskInfo) (map[int]sgdisk.Partition, error) {
|
||||
partitions := []sgdisk.Partition{}
|
||||
for _, cpart := range dev.Partitions {
|
||||
partitions = append(partitions, sgdisk.Partition{
|
||||
@@ -182,7 +182,7 @@ func (s stage) getRealStartAndSize(dev types.Disk, devAlias string, diskInfo uti
|
||||
return nil, err
|
||||
}
|
||||
|
||||
- result := []sgdisk.Partition{}
|
||||
+ result := map[int]sgdisk.Partition{}
|
||||
for _, part := range partitions {
|
||||
if dims, ok := realDimensions[part.Number]; ok {
|
||||
if part.StartSector != nil {
|
||||
@@ -192,7 +192,7 @@ func (s stage) getRealStartAndSize(dev types.Disk, devAlias string, diskInfo uti
|
||||
part.SizeInSectors = &dims.size
|
||||
}
|
||||
}
|
||||
- result = append(result, part)
|
||||
+ result[part.Number] = part
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -486,9 +486,9 @@ func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
- var partxAdd []uint64
|
||||
- var partxDelete []uint64
|
||||
- var partxUpdate []uint64
|
||||
+ var partxAdd []int
|
||||
+ var partxDelete []int
|
||||
+ var partxUpdate []int
|
||||
|
||||
for _, part := range resolvedPartitions {
|
||||
shouldExist := partitionShouldExist(part)
|
||||
@@ -510,13 +510,13 @@ func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
|
||||
case !exists && shouldExist:
|
||||
op.CreatePartition(part)
|
||||
modification = true
|
||||
- partxAdd = append(partxAdd, uint64(part.Number))
|
||||
+ partxAdd = append(partxAdd, part.Number)
|
||||
case exists && !shouldExist && !wipeEntry:
|
||||
return fmt.Errorf("partition %d exists but is specified as nonexistant and wipePartitionEntry is false", part.Number)
|
||||
case exists && !shouldExist && wipeEntry:
|
||||
op.DeletePartition(part.Number)
|
||||
modification = true
|
||||
- partxDelete = append(partxDelete, uint64(part.Number))
|
||||
+ partxDelete = append(partxDelete, part.Number)
|
||||
case exists && shouldExist && matches:
|
||||
s.Info("partition %d found with correct specifications", part.Number)
|
||||
case exists && shouldExist && !wipeEntry && !matches:
|
||||
@@ -530,7 +530,7 @@ func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
|
||||
part.StartSector = &info.StartSector
|
||||
op.CreatePartition(part)
|
||||
modification = true
|
||||
- partxUpdate = append(partxUpdate, uint64(part.Number))
|
||||
+ partxUpdate = append(partxUpdate, part.Number)
|
||||
} else {
|
||||
return fmt.Errorf("partition %d didn't match: %v", part.Number, matchErr)
|
||||
}
|
||||
@@ -539,7 +539,7 @@ func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
|
||||
op.DeletePartition(part.Number)
|
||||
op.CreatePartition(part)
|
||||
modification = true
|
||||
- partxUpdate = append(partxUpdate, uint64(part.Number))
|
||||
+ partxUpdate = append(partxUpdate, part.Number)
|
||||
default:
|
||||
// unfortunatey, golang doesn't check that all cases are handled exhaustively
|
||||
return fmt.Errorf("unreachable code reached when processing partition %d. golang--", part.Number)
|
||||
@@ -558,9 +558,9 @@ func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
|
||||
// kernel partition table with BLKPG but only uses BLKRRPART which fails
|
||||
// as soon as one partition of the disk is mounted
|
||||
if len(activeParts) > 0 {
|
||||
- runPartxCommand := func(op string, partitions []uint64) error {
|
||||
+ runPartxCommand := func(op string, partitions []int) error {
|
||||
for _, partNr := range partitions {
|
||||
- cmd := exec.Command(distro.PartxCmd(), "--"+op, "--nr", strconv.FormatUint(partNr, 10), blockDevResolved)
|
||||
+ cmd := exec.Command(distro.PartxCmd(), "--"+op, "--nr", fmt.Sprint(partNr), blockDevResolved)
|
||||
if _, err := s.LogCmd(cmd, "triggering partition %d %s on %q", partNr, op, devAlias); err != nil {
|
||||
return fmt.Errorf("partition %s failed: %v", op, err)
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@ -0,0 +1,101 @@
|
||||
From 305f9601c8968a993eaefc5ed251fa8ead26140a Mon Sep 17 00:00:00 2001
|
||||
From: James Le Cuirot <jlecuirot@microsoft.com>
|
||||
Date: Fri, 8 May 2026 17:58:38 +0100
|
||||
Subject: [PATCH 2/2] stages/disks: Allow partx to fail then check the state
|
||||
later
|
||||
|
||||
`partx --add` will fail if the kernel is already aware of the new
|
||||
partition. It was always theoretically possible that udev might trigger
|
||||
early, and that appears to be happening now.
|
||||
|
||||
Allow partx to fail and then check that added/updated partitions have
|
||||
the right start sector and size and that deleted partitions are absent
|
||||
once udev has settled.
|
||||
|
||||
Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
|
||||
---
|
||||
internal/exec/stages/disks/partitions.go | 62 ++++++++++++++++++++----
|
||||
1 file changed, 53 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/internal/exec/stages/disks/partitions.go b/internal/exec/stages/disks/partitions.go
|
||||
index 469ba77f..8b7d859b 100644
|
||||
--- a/internal/exec/stages/disks/partitions.go
|
||||
+++ b/internal/exec/stages/disks/partitions.go
|
||||
@@ -567,15 +567,9 @@ func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
- if err := runPartxCommand("delete", partxDelete); err != nil {
|
||||
- return err
|
||||
- }
|
||||
- if err := runPartxCommand("update", partxUpdate); err != nil {
|
||||
- return err
|
||||
- }
|
||||
- if err := runPartxCommand("add", partxAdd); err != nil {
|
||||
- return err
|
||||
- }
|
||||
+ runPartxCommand("delete", partxDelete)
|
||||
+ runPartxCommand("update", partxUpdate)
|
||||
+ runPartxCommand("add", partxAdd)
|
||||
}
|
||||
|
||||
// It's best to wait here for the /dev/ABC entries to be
|
||||
@@ -586,5 +580,55 @@ func (s stage) partitionDisk(dev types.Disk, devAlias string) error {
|
||||
return fmt.Errorf("failed to wait for udev on %q after partitioning: %v", devAlias, err)
|
||||
}
|
||||
|
||||
+ for _, partNum := range append(append([]int{}, partxAdd...), partxUpdate...) {
|
||||
+ part := resolvedPartitions[partNum]
|
||||
+ partDev := fmt.Sprintf("%s%s%d", blockDevResolved, prefix, partNum)
|
||||
+ sysBlockDir := fmt.Sprintf("/sys/class/block/%s/", filepath.Base(partDev))
|
||||
+
|
||||
+ // sysfs always reports in 512-byte sectors; convert our expected
|
||||
+ // values from logical sectors to 512-byte sectors for comparison
|
||||
+ logicalTo512 := int64(diskInfo.LogicalSectorSize) / 512
|
||||
+
|
||||
+ startStr, err := os.ReadFile(sysBlockDir + "start")
|
||||
+ if err != nil {
|
||||
+ return fmt.Errorf("failed to read start of %q from sysfs: %v", partDev, err)
|
||||
+ }
|
||||
+ kernelStart, err := strconv.ParseInt(strings.TrimSpace(string(startStr)), 10, 64)
|
||||
+ if err != nil {
|
||||
+ return fmt.Errorf("failed to parse start of %q from sysfs: %v", partDev, err)
|
||||
+ }
|
||||
+ if part.StartSector != nil {
|
||||
+ expectedStart := *part.StartSector * logicalTo512
|
||||
+ if kernelStart != expectedStart {
|
||||
+ return fmt.Errorf("kernel partition start for %q does not match expected (%d != %d 512-byte sectors)", partDev, kernelStart, expectedStart)
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ sizeStr, err := os.ReadFile(sysBlockDir + "size")
|
||||
+ if err != nil {
|
||||
+ return fmt.Errorf("failed to read size of %q from sysfs: %v", partDev, err)
|
||||
+ }
|
||||
+ kernelSize, err := strconv.ParseInt(strings.TrimSpace(string(sizeStr)), 10, 64)
|
||||
+ if err != nil {
|
||||
+ return fmt.Errorf("failed to parse size of %q from sysfs: %v", partDev, err)
|
||||
+ }
|
||||
+ if part.SizeInSectors != nil {
|
||||
+ expectedSize := *part.SizeInSectors * logicalTo512
|
||||
+ if kernelSize != expectedSize {
|
||||
+ return fmt.Errorf("kernel partition size for %q does not match expected (%d != %d 512-byte sectors)", partDev, kernelSize, expectedSize)
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for _, partNum := range partxDelete {
|
||||
+ partDev := fmt.Sprintf("%s%s%d", blockDevResolved, prefix, partNum)
|
||||
+ _, err := os.Stat(partDev)
|
||||
+ if err == nil {
|
||||
+ return fmt.Errorf("%q unexpectedly exists after partitioning", partDev)
|
||||
+ } else if !os.IsNotExist(err) {
|
||||
+ return fmt.Errorf("failed to stat %q after partitioning: %v", partDev, err)
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
return nil
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@ -35,6 +35,8 @@ else
|
||||
"${FILESDIR}/0017-docs-Add-re-added-platforms-to-docs-to-pass-tests.patch"
|
||||
"${FILESDIR}/0018-usr-share-oem-oem.patch"
|
||||
"${FILESDIR}/0019-internal-exec-stages-mount-Mount-oem.patch"
|
||||
"${FILESDIR}/0019-stages-disks-Make-getRealStartAndSize-return-a-map-l.patch"
|
||||
"${FILESDIR}/0020-stages-disks-Allow-partx-to-fail-then-check-the-stat.patch"
|
||||
)
|
||||
fi
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user