[Spec] support editing partition tables in curtin

Status Pending Review
Author @mwhudson
Release Ubuntu 22.04
Internal ID FO002

Abstract

Curtin can currently completely repartition a disk (removing all existing partitions) or install to an existing partition but it cannot do anything in between such as adding a partition in empty space.

Rationale

The lack of support for this sort of thing is already pretty embarrassing in the server installer but it is more or less unacceptable for the desktop installer, where dual boot installations are much more common.

Specification

Curtin and partition numbering

curtin’s behaviour at the time of writing wrt partition numbering at follows is: if a partition action does not include a number, then it is defined by ordering in list of actions:

  • for a logical partition, the number is 5 + (the number of logical partitions for this device before this one in the config)
    • in fact, given how logical partition numbering works, this is always the number for the partition (any explicit number is ignored)
  • for other partitions the number is 1+ (the number of partitions for this device before this one in the config)
  • there appears to be no explicit checking that this does not result in conflicts (although conflicts will I think always cause an installation failure)

I do not propose changing this at this time but I might make it more explicit and check for conflicts.

In practice there are two reasonable options here: either none of the partition actions for a device should be explicitly numbered or all of them should be (both MAAS and subiquity do the latter).

Curtin config changes

We will introduce a new curtin storage config version, 2, and interpret partition (and lvm_partition) a little differently:

  • If a partition (identified by number) isn’t referenced by an action with preserve=true it gets deleted (and has the first and last 1MiB wiped)
    • The endpoint of this behaviour is that if there are no preserve=true partitions, the whole partition table gets deleted
      • tangential thought: I think this makes preserve on disk actions meaningless
  • If the offset is specified, it is honoured (currently it is accepted but ignored)
  • If offset is not specified:
    • The primary partition with the least number goes 1MiB into the disk
    • For other primary partitions, find the partition with the next lowest number and set offset to the end of that, rounded up to 1MiB
    • The logical partition with the least number of partitions goes 1MiB into the extended partition
    • For other logical partitions, find the logical partition with the next lowest number and set offset to 512 bytes past the end of that, rounded up to 1MiB
    • This only changes the existing behaviour in two ways:
      • It makes it possible to create (or verify) a partition table that has no partition numbered 1 (I think this will fail currently)
      • If partition’s end is not on a 1MiB boundary (either because its start or its length is not 1MiB aligned) it will still align a subsequent partition to a 1MiB boundary
  • In a partition action with preserve=true, a new flag, modify=true indicates that the size value (and flag value, at least as far as that applies to partition type codes) is now an instruction to change the partition, not just a thing to check
    • looks like we can support resizing ntfs, fat, ext* and to-be-reformatted partitions
      • bitlocker will need to be disabled, but that’s true anyway
    • we will forbid resizing a partition that’s being used by a pre-existing compound device (raid, lvm)

This proposal does not cover moving partitions at all.

The “deleting unreferenced” and “resizing” bits should apply to LVM logical volumes too (offset doesn’t make sense).

Implementation

I think we should change disk_handler to process partitions for the device as well. specifically, it should work in this order:

  • Find all partition actions referencing this disk
  • Allocate numbers to partitions
  • Delete any unreferenced partitions
    • Including zapping 1MiB at start and end of any deleted partition
  • Resize any partitions that need to be resized
    • Including resizing any preserved filesystem of course
  • Finally, create new partitions (in number order)
    • Including computation of offset if needed
  • It might be easier in practice to compute the new partition table and just do it all in one sfdisk (or fdasd!) call

Braindump

  • How far to go?
    • i.e. do we try to make the whole thing more human friendly?
      • no
  • How procedural vs declarative to go?
    • revealing question here: how to represent deletion of a partition?
      • could delete unreferenced partitions, or could have an action with no size, or an explicit “delete this partition” action
        • it’s easier for the frontends to just describe what they want and have curtin figure out how to get from here to there
    • Do we just have a list of partitions in a disk / raid?
      • And lvs in a vg presumably
      • if you do this they still need an id at least
      • probably most orthogonal to have partitions/lvs at top level still but still need to get away from idea that entries in the list are “actions” i think
    • the minimal syntax extension is something like: “partition actions must have a number” and partition not referenced by a preserve=true partition gets deleted
      • this still requires scanning the action list to make any sense
      • also needs to handle offset stuff
      • i suppose i also need to think a bit harder about alignment
  • How to identify partitions?
    • Ways to order partitions:
      • order on disk
      • order in curtin config
      • order in partition table
    • I think index into partition table is only sane option here
  • Do we want to think about zfs or btrfs subvolumes at all here
    • not really!
  • MBR primary/logical/extended aaaaaaa
    • probably pretty annoying but also not that bad in the grand scheme of things
  • moving / resizing partitions aaaaaa
    • moving partitions sounds like pain wrt ordering of operations, fortunately i don’t think it’s required