Skip to content

Commit

Permalink
fix[close #273]: Old kernel files are not deleted
Browse files Browse the repository at this point in the history
  • Loading branch information
mirkobrombin committed May 6, 2024
1 parent fcc4db1 commit 10abc7b
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 57 deletions.
50 changes: 2 additions & 48 deletions core/grub.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"path/filepath"
"strings"

"github.com/hashicorp/go-version"
"github.com/vanilla-os/abroot/settings"
)

Expand All @@ -33,8 +32,7 @@ type Grub struct {
}

// generateABGrubConf generates a new grub config with the given details
// kernel version is automatically detected
func generateABGrubConf(rootPath string, rootUuid string, rootLabel string, generatedGrubConfigPath string) error {
func generateABGrubConf(kernelVersion string, rootPath string, rootUuid string, rootLabel string, generatedGrubConfigPath string) error {
PrintVerboseInfo("generateABGrubConf", "generating grub config for ABRoot")

kargs, err := KargsRead()
Expand All @@ -43,11 +41,10 @@ func generateABGrubConf(rootPath string, rootUuid string, rootLabel string, gene
return err
}

var grubPath, bootPrefix, bootPath, systemRoot string
var grubPath, bootPrefix, systemRoot string
if settings.Cnf.ThinProvisioning {
grubPath = filepath.Join(rootPath, "boot", "init", rootLabel)
bootPrefix = "/" + rootLabel
bootPath = grubPath

diskM := NewDiskManager()
sysRootPart, err := diskM.GetPartitionByLabel(rootLabel)
Expand All @@ -59,7 +56,6 @@ func generateABGrubConf(rootPath string, rootUuid string, rootLabel string, gene
} else {
grubPath = filepath.Join(rootPath, "boot", "grub")
bootPrefix = "/.system/boot"
bootPath = filepath.Join(rootPath, "boot")
systemRoot = "UUID=" + rootUuid
}

Expand All @@ -69,13 +65,6 @@ func generateABGrubConf(rootPath string, rootUuid string, rootLabel string, gene
initrd %s/initrd.img-%s
`

kernelVersion := getKernelVersion(bootPath)
if kernelVersion == "" {
err := errors.New("could not get kernel version")
PrintVerboseErr("generateABGrubConf", 1, err)
return err
}

err = os.MkdirAll(grubPath, 0755)
if err != nil {
PrintVerboseErr("generateABGrubConf", 2, err)
Expand Down Expand Up @@ -110,41 +99,6 @@ func generateABGrubConf(rootPath string, rootUuid string, rootLabel string, gene
return nil
}

// getKernelVersion returns the latest kernel version available in the root
func getKernelVersion(bootPath string) string {
PrintVerboseInfo("getKernelVersion", "running...")

kernelDir := filepath.Join(bootPath, "vmlinuz-*")
files, err := filepath.Glob(kernelDir)
if err != nil {
PrintVerboseErr("getKernelVersion", 0, err)
return ""
}

if len(files) == 0 {
PrintVerboseErr("getKernelVersion", 1, errors.New("no kernel found"))
return ""
}

var maxVer *version.Version
for _, file := range files {
verStr := filepath.Base(file)[8:]
ver, err := version.NewVersion(verStr)
if err != nil {
continue
}
if maxVer == nil || ver.GreaterThan(maxVer) {
maxVer = ver
}
}

if maxVer != nil {
return maxVer.String()
}

return ""
}

// NewGrub creates a new Grub instance
func NewGrub(bootPart Partition) (*Grub, error) {
PrintVerboseInfo("NewGrub", "running...")
Expand Down
93 changes: 93 additions & 0 deletions core/kernel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package core

/* License: GPLv3
Authors:
Mirko Brombin <[email protected]>
Vanilla OS Contributors <https://github.com/vanilla-os/>
Copyright: 2024
Description:
ABRoot is utility which provides full immutability and
atomicity to a Linux system, by transacting between
two root filesystems. Updates are performed using OCI
images, to ensure that the system is always in a
consistent state.
*/

import (
"errors"
"fmt"
"os"
"path"
"path/filepath"
"strings"

"github.com/hashicorp/go-version"
)

// getKernelVersion returns the latest kernel version available in the root
func getKernelVersion(bootPath string) string {
PrintVerboseInfo("getKernelVersion", "running...")

kernelDir := filepath.Join(bootPath, "vmlinuz-*")
files, err := filepath.Glob(kernelDir)
if err != nil {
PrintVerboseErr("getKernelVersion", 0, err)
return ""
}

if len(files) == 0 {
PrintVerboseErr("getKernelVersion", 1, errors.New("no kernel found"))
return ""
}

var maxVer *version.Version
for _, file := range files {
verStr := filepath.Base(file)[8:]
ver, err := version.NewVersion(verStr)
if err != nil {
continue
}
if maxVer == nil || ver.GreaterThan(maxVer) {
maxVer = ver
}
}

if maxVer != nil {
return maxVer.String()
}

return ""
}

// cleanupOldKernels removes kernels not used by future root from the
// init partition.
//
// NOTE: this only works with LVM Think Provisioning turned on in ABRoot. Also
// note that this function explicitly removes all kernels except the
// one passed as argument, we can't just remove older versions because
// the kernel versioning is not guaranteed to be incremental, e.g. an
// update could introduce an older kernel version.
func cleanupOldKernels(newKernelVer string, initMountpoint string, partFuture string) (err error) {
fmt.Println(path.Join(initMountpoint, partFuture))
files, err := os.ReadDir(path.Join(initMountpoint, partFuture))
if err != nil {
return
}

for _, file := range files {
if strings.HasPrefix(file.Name(), "vmlinuz-") && file.Name() != "vmlinuz-"+newKernelVer {
err = os.Remove(path.Join(initMountpoint, partFuture, file.Name()))
if err != nil {
return
}
}
if strings.HasPrefix(file.Name(), "initrd.img-") && file.Name() != "initrd.img-"+newKernelVer {
err = os.Remove(path.Join(initMountpoint, partFuture, file.Name()))
if err != nil {
return
}
}
}

return nil
}
52 changes: 43 additions & 9 deletions core/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -665,17 +665,25 @@ func (s *ABSystem) RunOperation(operation ABSystemOperation) error {
return err
}

newKernelVer := getKernelVersion(filepath.Join(systemNew, "boot"))
if newKernelVer == "" {
err := errors.New("could not get kernel version")
PrintVerboseErr("ABSystem.RunOperation", 7.26, err)
return err
}

var rootUuid string
// If Thin-Provisioning set, mount init partition and move linux and initrd
// images to it
// images to it.
var initMountpoint string
if settings.Cnf.ThinProvisioning {
initPartition, err := s.RootM.GetInit()
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 7.3, err)
return err
}

initMountpoint := filepath.Join(systemNew, "boot", "init")
initMountpoint = filepath.Join(systemNew, "boot", "init")
err = initPartition.Mount(initMountpoint)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 7.4, err)
Expand All @@ -686,33 +694,33 @@ func (s *ABSystem) RunOperation(operation ABSystemOperation) error {
return initPartition.Unmount()
}, nil, 80, &goodies.NoErrorHandler{}, false)

kernelVersion := getKernelVersion(filepath.Join(systemNew, "boot"))
err = CopyFile(
filepath.Join(systemNew, "boot", "vmlinuz-"+kernelVersion),
filepath.Join(initMountpoint, partFuture.Label, "vmlinuz-"+kernelVersion),
filepath.Join(systemNew, "boot", "vmlinuz-"+newKernelVer),
filepath.Join(initMountpoint, partFuture.Label, "vmlinuz-"+newKernelVer),
)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 7.5, err)
return err
}
err = CopyFile(
filepath.Join(systemNew, "boot", "initrd.img-"+kernelVersion),
filepath.Join(initMountpoint, partFuture.Label, "initrd.img-"+kernelVersion),
filepath.Join(systemNew, "boot", "initrd.img-"+newKernelVer),
filepath.Join(initMountpoint, partFuture.Label, "initrd.img-"+newKernelVer),
)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 7.6, err)
return err
}

os.Remove(filepath.Join(systemNew, "boot", "vmlinuz-"+kernelVersion))
os.Remove(filepath.Join(systemNew, "boot", "initrd.img-"+kernelVersion))
os.Remove(filepath.Join(systemNew, "boot", "vmlinuz-"+newKernelVer))
os.Remove(filepath.Join(systemNew, "boot", "initrd.img-"+newKernelVer))

rootUuid = initPartition.Uuid
} else {
rootUuid = partFuture.Partition.Uuid
}

err = generateABGrubConf(
newKernelVer,
systemNew,
rootUuid,
partFuture.Label,
Expand Down Expand Up @@ -858,6 +866,32 @@ func (s *ABSystem) RunOperation(operation ABSystemOperation) error {
}
}

// Stage 12: Cleanup old kernel images
// ------------------------------------------------
// If Thin-Provisioning set, we have to remove the old kernel images
// from the init partition since it is too small to hold multiple kernels.
// This step runs as the last one to ensure the whole transaction is
// successful before removing the old kernels.
if settings.Cnf.ThinProvisioning {
switch operation {
case DRY_RUN_UPGRADE, DRY_RUN_APPLY, DRY_RUN_INITRAMFS:
default:
PrintVerboseSimple("[Stage 12] -------- ABSystemRunOperation")

// since we did the swap, the init partition is now mounted in
// .system instead of .system.new, so we need to update the path
// before proceeding
systemNew := filepath.Join(partFuture.Partition.MountPoint, ".system")
initMountpoint = filepath.Join(systemNew, "boot", "init")

err = cleanupOldKernels(newKernelVer, initMountpoint, partFuture.Label)
if err != nil {
PrintVerboseErr("ABSystem.RunOperation", 12, err)
return err
}
}
}

PrintVerboseInfo("ABSystem.RunOperation", "upgrade completed")
return nil
}
Expand Down

0 comments on commit 10abc7b

Please sign in to comment.