-
Notifications
You must be signed in to change notification settings - Fork 650
many: make kernel-modules components available on initramfs installation #14810
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
32e8a2e
4e85be2
d1c93a5
1736cec
eb5b50c
d39de47
caf563f
a167da8
f6ab58a
d29061e
9dcf60b
5a8cded
0969574
ac13f3c
ff3bc0f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -57,6 +57,7 @@ | |
| "github.com/snapcore/snapd/seed" | ||
| "github.com/snapcore/snapd/snap" | ||
| "github.com/snapcore/snapd/snap/naming" | ||
| "github.com/snapcore/snapd/snap/snapdir" | ||
| "github.com/snapcore/snapd/snap/squashfs" | ||
| "github.com/snapcore/snapd/sysconfig" | ||
| "github.com/snapcore/snapd/timings" | ||
|
|
@@ -258,13 +259,27 @@ | |
| if err != nil { | ||
| return nil, err | ||
| } | ||
| // Comes from the seed and it might be unasserted, set revision in that case | ||
| if info.Revision.Unset() { | ||
| info.Revision = snap.R(-1) | ||
| } | ||
| return info, nil | ||
|
|
||
| } | ||
|
|
||
| func readComponentInfo(seedComp *seed.Component, mntPt string, snapInfo *snap.Info, csi *snap.ComponentSideInfo) (*snap.ComponentInfo, error) { | ||
| container := snapdir.New(mntPt) | ||
| ci, err := snap.ReadComponentInfoFromContainer(container, snapInfo, csi) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| // Comes from the seed and it might be unasserted, set revision in that case | ||
| if ci.Revision.Unset() { | ||
| ci.Revision = snap.R(-1) | ||
| } | ||
| return ci, nil | ||
| } | ||
|
|
||
| func runFDESetupHook(req *fde.SetupRequest) ([]byte, error) { | ||
| // TODO: use systemd-run | ||
| encoded, err := json.Marshal(req) | ||
|
|
@@ -331,26 +346,77 @@ | |
| return fmt.Errorf("cannot use gadget: %v", err) | ||
| } | ||
|
|
||
| // TODO:COMPS take into account kernel-modules components, see | ||
| // DeviceManager,doSetupRunSystem and other parts of | ||
| // handlers_install.go. | ||
| // Get kernel-modules information to have them ready early on first boot | ||
|
|
||
| bootDevice := "" | ||
| kernelSnapInfo := &gadgetInstall.KernelSnapInfo{ | ||
| Name: kernelSnap.SnapName(), | ||
| MountPoint: kernelMountDir, | ||
| Revision: kernelSnap.Revision, | ||
| // Should be true always anyway | ||
| IsCore: !model.Classic(), | ||
| } | ||
| switch model.Base() { | ||
| case "core20", "core22", "core22-desktop": | ||
| kernelSnapInfo.NeedsDriversTree = false | ||
| default: | ||
| kernelSnapInfo.NeedsDriversTree = true | ||
| kernCompsByName := make(map[string]*snap.Component) | ||
| for _, c := range kernelSnap.Components { | ||
| kernCompsByName[c.Name] = c | ||
| } | ||
|
|
||
| kernelSeed := sysSnaps[snap.TypeKernel] | ||
| kernCompsMntPts := make(map[string]string) | ||
| compSeedInfos := []install.ComponentSeedInfo{} | ||
| for _, sc := range kernelSeed.Components { | ||
| seedComp := sc | ||
| comp, ok := kernCompsByName[seedComp.CompSideInfo.Component.ComponentName] | ||
| if !ok { | ||
| return fmt.Errorf("component %s in seed but not defined by snap!", | ||
| seedComp.CompSideInfo.Component.ComponentName) | ||
| } | ||
| if comp.Type != snap.KernelModulesComponent { | ||
| continue | ||
| } | ||
|
|
||
| // Mount ephemerally the kernel-modules components to read | ||
| // their metadata and also to make them accessible if building | ||
| // the drivers tree. | ||
| mntPt := filepath.Join(filepath.Join(boot.InitramfsRunMntDir, "snap-content", | ||
| seedComp.CompSideInfo.Component.String())) | ||
| if err := doSystemdMount(seedComp.Path, mntPt, &systemdMountOptions{ | ||
| ReadOnly: true, | ||
| Private: true, | ||
| Ephemeral: true}); err != nil { | ||
| return err | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need a test in this error case to ensure the unmounts are called correctly?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added a test now |
||
| } | ||
| kernCompsMntPts[seedComp.CompSideInfo.Component.String()] = mntPt | ||
|
|
||
| defer func() { | ||
| stdout, stderr, err := osutil.RunSplitOutput("systemd-mount", "--umount", mntPt) | ||
| if err != nil { | ||
| logger.Noticef("cannot unmount component in %s: %v", | ||
| mntPt, osutil.OutputErrCombine(stdout, stderr, err)) | ||
| } | ||
| }() | ||
|
|
||
| compInfo, err := readComponentInfo(&seedComp, mntPt, kernelSnap, &seedComp.CompSideInfo) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| compSeedInfos = append(compSeedInfos, install.ComponentSeedInfo{ | ||
| Info: compInfo, | ||
| Seed: &seedComp, | ||
| }) | ||
| } | ||
|
|
||
| installedSystem, err := gadgetInstallRun(model, gadgetMountDir, kernelSnapInfo, bootDevice, options, installObserver, timings.New(nil)) | ||
| currentSeed, err := mst.LoadSeed(mst.recoverySystem) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| preseedSeed, ok := currentSeed.(seed.PreseedCapable) | ||
| preseed := false | ||
| if ok && preseedSeed.HasArtifact("preseed.tgz") { | ||
| preseed = true | ||
| } | ||
| // Drivers tree will already be built if using the preseed tarball | ||
| needsKernelSetup := kernel.NeedsKernelDriversTree(model) && !preseed | ||
|
|
||
| isCore := !model.Classic() | ||
| kernelBootInfo := install.BuildKernelBootInfo( | ||
| kernelSnap, compSeedInfos, kernelMountDir, kernCompsMntPts, | ||
| install.BuildKernelBootInfoOpts{IsCore: isCore, NeedsDriversTree: needsKernelSetup}) | ||
|
|
||
| bootDevice := "" | ||
| installedSystem, err := gadgetInstallRun(model, gadgetMountDir, kernelBootInfo.KSnapInfo, bootDevice, options, installObserver, timings.New(nil)) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
@@ -382,6 +448,7 @@ | |
| KernelPath: sysSnaps[snap.TypeKernel].Path, | ||
| UnpackedGadgetDir: gadgetMountDir, | ||
| RecoverySystemLabel: mst.recoverySystem, | ||
| KernelMods: kernelBootInfo.BootableKMods, | ||
| } | ||
|
|
||
| if err := bootMakeRunnableStandaloneSystem(model, bootWith, trustedInstallObserver); err != nil { | ||
|
|
@@ -395,15 +462,27 @@ | |
| return err | ||
| } | ||
|
|
||
| currentSeed, err := mst.LoadSeed(mst.recoverySystem) | ||
| if preseed { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A comment about why different behavior is required for this case would be nice
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added |
||
| // Extract pre-seed tarball | ||
| runMode := false | ||
| if err := installApplyPreseededData(preseedSeed, | ||
| boot.InitramfsWritableDir(model, runMode)); err != nil { | ||
| return err | ||
| } | ||
| } | ||
|
|
||
| // Create drivers tree mount units to make it available before switch root | ||
| rootfsDir := filepath.Join(boot.InitramfsDataDir, "system-data") | ||
| hasDriversTree, err := createKernelMounts( | ||
| rootfsDir, kernelSnap.SnapName(), kernelSnap.Revision, !isCore) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| preseedSeed, ok := currentSeed.(seed.PreseedCapable) | ||
| if ok && preseedSeed.HasArtifact("preseed.tgz") { | ||
| runMode := false | ||
| if err := installApplyPreseededData(preseedSeed, boot.InitramfsWritableDir(model, runMode)); err != nil { | ||
| return err | ||
| if hasDriversTree { | ||
| // Unmount the kernel snap mount, we keep it only for UC20/22 | ||
| stdout, stderr, err := osutil.RunSplitOutput("systemd-mount", "--umount", kernelMountDir) | ||
| if err != nil { | ||
| return osutil.OutputErrCombine(stdout, stderr, err) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -432,6 +511,25 @@ | |
| } | ||
|
|
||
| if installAndRun { | ||
| kernSnap := snaps[snap.TypeKernel] | ||
| // seed is cached at this point | ||
| theSeed, err := mst.LoadSeed("") | ||
| if err != nil { | ||
| return fmt.Errorf("internal error: cannot load seed: %v", err) | ||
| } | ||
| // Filter by mode, this is relevant only to get the | ||
| // kernel-modules components that are used in run mode and | ||
| // therefore need to be considered when installing from the | ||
| // initramfs to have the modules available early on first boot. | ||
| // TODO when running normal install or recover/factory-reset, | ||
| // we would need also this if we want the modules to be | ||
| // available early. | ||
| kernSnap, err = theSeed.ModeSnap(kernSnap.SnapName(), "run") | ||
| if err != nil { | ||
| return err | ||
| } | ||
| snaps[snap.TypeKernel] = kernSnap | ||
|
|
||
| if err := doInstall(mst, model, snaps); err != nil { | ||
| return err | ||
| } | ||
|
|
@@ -1979,9 +2077,9 @@ | |
|
|
||
| // First in modules (we might not have a kernel version subdir if there | ||
| // are no kernel modules). | ||
| kversion, kverr := kernel.KernelVersionFromModulesDir(filepath.Join(driversDir, "lib")) | ||
| kversion, kver := kernel.KernelVersionFromModulesDir(filepath.Join(driversDir, "lib")) | ||
| compSet := map[snap.ComponentSideInfo]bool{} | ||
| if kverr == nil { | ||
| if kver == nil { | ||
| modUpdatesDir := filepath.Join(driversDir, "lib", "modules", kversion, "updates") | ||
| if err := getCompsFromSymlinks(modUpdatesDir, kernelName, compSet); err != nil { | ||
| return err | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In what cases are the revision unset? And why does it need to be set to x1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When reading from the seed, if the component is unasserted. Note that this is the same that was being done for snaps in
readSnapInfo. I've added comments to clarify.