Skip to content

Commit

Permalink
fix: lock provisioning order of user disk partitions
Browse files Browse the repository at this point in the history
Fixes #9877

As a side-effect, fix alignment of user disks for newer QEMU versions.

Signed-off-by: Andrey Smirnov <[email protected]>
  • Loading branch information
smira committed Dec 5, 2024
1 parent d0773ff commit dd61ad8
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 8 deletions.
6 changes: 4 additions & 2 deletions cmd/talosctl/cmd/mgmt/cluster/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -1162,6 +1162,8 @@ func parseCPUShare(cpus string) (int64, error) {
}

func getDisks() ([]*provision.Disk, error) {
const GPTAlignment = 2 * 1024 * 1024 // 2 MB

// should have at least a single primary disk
disks := []*provision.Disk{
{
Expand Down Expand Up @@ -1211,8 +1213,8 @@ func getDisks() ([]*provision.Disk, error) {
}

disks = append(disks, &provision.Disk{
// add 1 MB to make extra room for GPT and alignment
Size: diskSize + 2*1024*1024,
// add 2 MB per partition to make extra room for GPT and alignment
Size: diskSize + GPTAlignment*uint64(len(diskPartitions)+1),
Partitions: diskPartitions,
SkipPreallocate: !clusterDiskPreallocate,
Driver: "ide",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,11 @@ func (ctrl *UserDiskConfigController) Run(ctx context.Context, r controller.Runt
vc.TypedSpec().Type = block.VolumeTypePartition

vc.TypedSpec().Provisioning = block.ProvisioningSpec{
Wave: block.WaveUserDisks,
// it's crucial to keep the order of provisioning locked within each disk, otherwise
// provisioning might order them different way, and create partitions in wrong order
// the matcher on partition idx would then discover partitions in wrong order, and mount them
// in wrong order
Wave: block.WaveLegacyUserDisks + idx,
DiskSelector: block.DiskSelector{
Match: diskPathMatch(resolvedDevicePath),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ func (suite *UserDiskConfigSuite) TestReconcileUserDisk() {
ctest.AssertResource(suite, id, func(r *block.VolumeConfig, asrt *assert.Assertions) {
asrt.NotEmpty(r.TypedSpec().Provisioning)
asrt.Contains(r.Metadata().Labels().Raw(), block.UserDiskLabel)
asrt.GreaterOrEqual(r.TypedSpec().Provisioning.Wave, block.WaveLegacyUserDisks)
})
}

Expand Down
5 changes: 3 additions & 2 deletions pkg/machinery/resources/block/volume_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@ type VolumeConfigSpec struct {

// Wave constants.
const (
WaveSystemDisk = -1
WaveUserDisks = 0
WaveSystemDisk = -1
WaveUserDisks = 0
WaveLegacyUserDisks = 1000000 // legacy user disks rely on specific order of provisioning
)

// ProvisioningSpec is the spec for volume provisioning.
Expand Down
9 changes: 6 additions & 3 deletions pkg/provision/providers/vm/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,13 @@ func (p *Provisioner) UserDiskName(index int) string {

// CreateDisks creates empty disk files for each disk.
func (p *Provisioner) CreateDisks(state *State, nodeReq provision.NodeRequest) (diskPaths []string, err error) {
const QEMUAlignment = 4 * 1024 * 1024 // 4 MiB, required by QEMU

diskPaths = make([]string, len(nodeReq.Disks))

for i, disk := range nodeReq.Disks {
diskPath := state.GetRelativePath(fmt.Sprintf("%s-%d.disk", nodeReq.Name, i))
diskSize := (disk.Size + QEMUAlignment - 1) / QEMUAlignment * QEMUAlignment

var diskF *os.File

Expand All @@ -38,13 +41,13 @@ func (p *Provisioner) CreateDisks(state *State, nodeReq provision.NodeRequest) (

defer diskF.Close() //nolint:errcheck

if err = diskF.Truncate(int64(disk.Size)); err != nil {
if err = diskF.Truncate(int64(diskSize)); err != nil {
return nil, err
}

if !disk.SkipPreallocate {
if err = syscall.Fallocate(int(diskF.Fd()), 0, 0, int64(disk.Size)); err != nil {
fmt.Fprintf(os.Stderr, "WARNING: failed to preallocate disk space for %q (size %d): %s", diskPath, disk.Size, err)
if err = syscall.Fallocate(int(diskF.Fd()), 0, 0, int64(diskSize)); err != nil {
fmt.Fprintf(os.Stderr, "WARNING: failed to preallocate disk space for %q (size %d): %s", diskPath, diskSize, err)
}
}

Expand Down

0 comments on commit dd61ad8

Please sign in to comment.