chore: cleanup partition code

Cleanup partition code to be explicit about `Format` and `Partition`
options.

Signed-off-by: Noel Georgi <git@frezbo.dev>
This commit is contained in:
Noel Georgi 2023-06-07 01:11:02 +05:30
parent 31b988281e
commit 1c0c7933df
No known key found for this signature in database
GPG Key ID: 21A9F444075C9E36
6 changed files with 206 additions and 94 deletions

View File

@ -360,7 +360,7 @@ func (m *Manifest) executeOnDevice(device Device, targets []*Target) (err error)
}
for i, target := range targets {
if err = target.Partition(pt, i, bd); err != nil {
if err = target.partition(pt, i); err != nil {
return fmt.Errorf("failed to partition device: %w", err)
}
}

View File

@ -14,8 +14,6 @@ import (
"os"
"path/filepath"
"github.com/dustin/go-humanize"
"github.com/siderolabs/go-blockdevice/blockdevice"
"github.com/siderolabs/go-blockdevice/blockdevice/partition/gpt"
"github.com/siderolabs/go-blockdevice/blockdevice/util"
"golang.org/x/sys/unix"
@ -31,6 +29,7 @@ import (
//nolint:maligned
type Target struct {
*partition.FormatOptions
*partition.Options
Device string
LegacyBIOSBootable bool
@ -99,6 +98,18 @@ func ParseTarget(label, deviceName string) (*Target, error) {
func EFITarget(device string, extra *Target) *Target {
target := &Target{
FormatOptions: partition.NewFormatOptions(constants.EFIPartitionLabel),
Options: partition.NewPartitionOptions(constants.EFIPartitionLabel, false),
Device: device,
}
return target.enhance(extra)
}
// EFITargetUKI builds the default EFI UKI target.
func EFITargetUKI(device string, extra *Target) *Target {
target := &Target{
FormatOptions: partition.NewFormatOptions(constants.EFIPartitionLabel),
Options: partition.NewPartitionOptions(constants.EFIPartitionLabel, true),
Device: device,
}
@ -109,6 +120,7 @@ func EFITarget(device string, extra *Target) *Target {
func BIOSTarget(device string, extra *Target) *Target {
target := &Target{
FormatOptions: partition.NewFormatOptions(constants.BIOSGrubPartitionLabel),
Options: partition.NewPartitionOptions(constants.BIOSGrubPartitionLabel, false),
Device: device,
LegacyBIOSBootable: true,
}
@ -120,6 +132,7 @@ func BIOSTarget(device string, extra *Target) *Target {
func BootTarget(device string, extra *Target) *Target {
target := &Target{
FormatOptions: partition.NewFormatOptions(constants.BootPartitionLabel),
Options: partition.NewPartitionOptions(constants.BootPartitionLabel, false),
Device: device,
}
@ -130,6 +143,7 @@ func BootTarget(device string, extra *Target) *Target {
func MetaTarget(device string, extra *Target) *Target {
target := &Target{
FormatOptions: partition.NewFormatOptions(constants.MetaPartitionLabel),
Options: partition.NewPartitionOptions(constants.MetaPartitionLabel, false),
Device: device,
}
@ -140,6 +154,7 @@ func MetaTarget(device string, extra *Target) *Target {
func StateTarget(device string, extra *Target) *Target {
target := &Target{
FormatOptions: partition.NewFormatOptions(constants.StatePartitionLabel),
Options: partition.NewPartitionOptions(constants.StatePartitionLabel, false),
Device: device,
}
@ -150,6 +165,7 @@ func StateTarget(device string, extra *Target) *Target {
func EphemeralTarget(device string, extra *Target) *Target {
target := &Target{
FormatOptions: partition.NewFormatOptions(constants.EphemeralPartitionLabel),
Options: partition.NewPartitionOptions(constants.EphemeralPartitionLabel, false),
Device: device,
}
@ -179,24 +195,21 @@ func (t *Target) String() string {
// Locate existing partition on the disk.
func (t *Target) Locate(pt *gpt.GPT) (*gpt.Partition, error) {
for _, part := range pt.Partitions().Items() {
if part.Name == t.Label {
var err error
t.PartitionName, err = part.Path()
if err != nil {
return part, err
}
return part, nil
}
part, err := partition.Locate(pt, t.Label)
if err != nil {
return nil, err
}
return nil, nil
t.PartitionName, err = part.Path()
if err != nil {
return nil, err
}
return part, nil
}
// Partition creates a new partition on the specified device.
func (t *Target) Partition(pt *gpt.GPT, pos int, bd *blockdevice.BlockDevice) (err error) {
// partition creates a new partition on the specified device.
func (t *Target) partition(pt *gpt.GPT, pos int) (err error) {
if t.Skip {
part := pt.Partitions().FindByName(t.Label)
if part != nil {
@ -211,32 +224,17 @@ func (t *Target) Partition(pt *gpt.GPT, pos int, bd *blockdevice.BlockDevice) (e
return nil
}
log.Printf("partitioning %s - %s %q\n", t.Device, t.Label, humanize.Bytes(t.Size))
opts := []gpt.PartitionOption{
gpt.WithPartitionType(t.PartitionType),
gpt.WithPartitionName(t.Label),
}
if t.Size == 0 {
opts = append(opts, gpt.WithMaximumSize(true))
}
if t.LegacyBIOSBootable {
opts = append(opts, gpt.WithLegacyBIOSBootableAttribute(true))
}
part, err := pt.InsertAt(pos, t.Size, opts...)
partitionName, err := partition.Partition(pt, pos, t.Device, partition.Options{
PartitionLabel: t.Label,
PartitionType: t.PartitionType,
Size: t.Size,
LegacyBIOSBootable: t.LegacyBIOSBootable,
})
if err != nil {
return err
}
t.PartitionName, err = part.Path()
if err != nil {
return err
}
log.Printf("created %s (%s) size %d blocks", t.PartitionName, t.Label, part.Length())
t.PartitionName = partitionName
return nil
}

View File

@ -1069,11 +1069,13 @@ func partitionAndFormatDisks(logger *log.Logger, r runtime.Runtime) error {
extraTarget := &installer.Target{
Device: disk.Device(),
FormatOptions: &partition.FormatOptions{
Size: part.Size(),
Force: true,
PartitionType: partition.LinuxFilesystemData,
FileSystemType: partition.FilesystemTypeXFS,
},
Options: &partition.Options{
Size: part.Size(),
PartitionType: partition.LinuxFilesystemData,
},
}
m.Targets[disk.Device()] = append(m.Targets[disk.Device()], extraTarget)

View File

@ -33,6 +33,10 @@ const (
EFISize = 100 * MiB
BIOSGrubSize = 1 * MiB
BootSize = 1000 * MiB
MetaSize = 1 * MiB
StateSize = 100 * MiB
// EFIUKISize is the size of the EFI partition when UKI is enabled.
// With UKI all assets are stored in the EFI partition.
// This is the size of the old EFISize + BIOSGrubSize + BootSize.
EFIUKISize = EFISize + BIOSGrubSize + BootSize
MetaSize = 1 * MiB
StateSize = 100 * MiB
)

View File

@ -18,20 +18,13 @@ import (
// FormatOptions contains format parameters.
type FormatOptions struct {
Label string
PartitionType Type
FileSystemType FileSystemType
Size uint64
Force bool
}
// NewFormatOptions creates a new format options.
func NewFormatOptions(label string) *FormatOptions {
opts, ok := systemPartitions[label]
if ok {
return &opts
}
return nil
return systemPartitionsFormatOptions(label)
}
// Format zeroes the device and formats it using filesystem type provided.
@ -69,47 +62,45 @@ func zeroPartition(devname string) (err error) {
return err
}
var systemPartitions = map[string]FormatOptions{
constants.EFIPartitionLabel: {
Label: constants.EFIPartitionLabel,
PartitionType: EFISystemPartition,
FileSystemType: FilesystemTypeVFAT,
Size: EFISize,
Force: true,
},
constants.BIOSGrubPartitionLabel: {
Label: constants.BIOSGrubPartitionLabel,
PartitionType: BIOSBootPartition,
FileSystemType: FilesystemTypeNone,
Size: BIOSGrubSize,
Force: true,
},
constants.BootPartitionLabel: {
Label: constants.BootPartitionLabel,
PartitionType: LinuxFilesystemData,
FileSystemType: FilesystemTypeXFS,
Size: BootSize,
Force: true,
},
constants.MetaPartitionLabel: {
Label: constants.MetaPartitionLabel,
PartitionType: LinuxFilesystemData,
FileSystemType: FilesystemTypeNone,
Size: MetaSize,
Force: true,
},
constants.StatePartitionLabel: {
Label: constants.StatePartitionLabel,
PartitionType: LinuxFilesystemData,
FileSystemType: FilesystemTypeXFS,
Size: StateSize,
Force: true,
},
constants.EphemeralPartitionLabel: {
Label: constants.EphemeralPartitionLabel,
PartitionType: LinuxFilesystemData,
FileSystemType: FilesystemTypeXFS,
Size: 0,
Force: true,
},
func systemPartitionsFormatOptions(label string) *FormatOptions {
switch label {
case constants.EFIPartitionLabel:
return &FormatOptions{
Label: constants.EFIPartitionLabel,
FileSystemType: FilesystemTypeVFAT,
Force: true,
}
case constants.BIOSGrubPartitionLabel:
return &FormatOptions{
Label: constants.BIOSGrubPartitionLabel,
FileSystemType: FilesystemTypeNone,
Force: true,
}
case constants.BootPartitionLabel:
return &FormatOptions{
Label: constants.BootPartitionLabel,
FileSystemType: FilesystemTypeXFS,
Force: true,
}
case constants.MetaPartitionLabel:
return &FormatOptions{
Label: constants.MetaPartitionLabel,
FileSystemType: FilesystemTypeNone,
Force: true,
}
case constants.StatePartitionLabel:
return &FormatOptions{
Label: constants.StatePartitionLabel,
FileSystemType: FilesystemTypeXFS,
Force: true,
}
case constants.EphemeralPartitionLabel:
return &FormatOptions{
Label: constants.EphemeralPartitionLabel,
FileSystemType: FilesystemTypeXFS,
Force: true,
}
default:
return nil
}
}

View File

@ -4,3 +4,120 @@
// Package partition provides common utils for system partition format.
package partition
import (
"log"
"github.com/dustin/go-humanize"
"github.com/siderolabs/go-blockdevice/blockdevice/partition/gpt"
"github.com/siderolabs/talos/pkg/machinery/constants"
)
// Options contains the options for creating a partition.
type Options struct {
PartitionLabel string
PartitionType Type
Size uint64
LegacyBIOSBootable bool
}
// NewPartitionOptions returns a new PartitionOptions.
func NewPartitionOptions(label string, uki bool) *Options {
return systemPartitionsPartitonOptions(label, uki)
}
// Locate existing partition on the disk by label.
func Locate(pt *gpt.GPT, label string) (*gpt.Partition, error) {
for _, part := range pt.Partitions().Items() {
if part.Name == label {
return part, nil
}
}
return nil, nil
}
// Partition creates a new partition on the specified device.
// Returns the path to the newly created partition.
func Partition(pt *gpt.GPT, pos int, device string, partitionOpts Options) (string, error) {
log.Printf("partitioning %s - %s %q\n", device, partitionOpts.PartitionLabel, humanize.Bytes(partitionOpts.Size))
opts := []gpt.PartitionOption{
gpt.WithPartitionType(partitionOpts.PartitionType),
gpt.WithPartitionName(partitionOpts.PartitionLabel),
}
if partitionOpts.Size == 0 {
opts = append(opts, gpt.WithMaximumSize(true))
}
if partitionOpts.LegacyBIOSBootable {
opts = append(opts, gpt.WithLegacyBIOSBootableAttribute(true))
}
part, err := pt.InsertAt(pos, partitionOpts.Size, opts...)
if err != nil {
return "", err
}
partitionName, err := part.Path()
if err != nil {
return "", err
}
log.Printf("created %s (%s) size %d blocks", partitionName, partitionOpts.PartitionLabel, part.Length())
return partitionName, nil
}
func systemPartitionsPartitonOptions(label string, uki bool) *Options {
switch label {
case constants.EFIPartitionLabel:
partitionOptions := &Options{
PartitionType: EFISystemPartition,
Size: EFISize,
}
if uki {
partitionOptions.Size = EFIUKISize
}
return partitionOptions
case constants.BIOSGrubPartitionLabel:
if uki {
panic("BIOS partition is not supported with UKI")
}
return &Options{
PartitionType: BIOSBootPartition,
Size: BIOSGrubSize,
}
case constants.BootPartitionLabel:
if uki {
panic("BOOT partition is not supported with UKI")
}
return &Options{
PartitionType: LinuxFilesystemData,
Size: BootSize,
}
case constants.MetaPartitionLabel:
return &Options{
PartitionType: LinuxFilesystemData,
Size: MetaSize,
}
case constants.StatePartitionLabel:
return &Options{
PartitionType: LinuxFilesystemData,
Size: StateSize,
}
case constants.EphemeralPartitionLabel:
return &Options{
PartitionType: LinuxFilesystemData,
Size: 0,
}
default:
return nil
}
}