Skip to content

Commit c9f736d

Browse files
committed
feat(runtime): bind boot artifacts from rootfs views
Load shim-prepared rootfs view state for block rootfs setup. Probe the view before unmounting the container rootfs, then bind the boot artifacts after prepareRoot in the block postSetup step. Signed-off-by: sidneychang <2190206983@qq.com>
1 parent 0e15b92 commit c9f736d

2 files changed

Lines changed: 71 additions & 34 deletions

File tree

pkg/unikontainers/block.go

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,16 @@ const tmpfsSizeForBlockRootfs = "65536k"
3636
var ErrMountpoint = errors.New("no FS is mounted in this mountpoint")
3737

3838
type blockRootfs struct {
39-
mounts []specs.Mount
40-
monRootfs string
41-
mountedPath string
42-
path string
43-
kernelPath string
44-
initrdPath string
45-
uruncJSONPath string
46-
guestType string
47-
guest types.Unikernel
39+
mounts []specs.Mount
40+
monRootfs string
41+
mountedPath string
42+
path string
43+
kernelPath string
44+
initrdPath string
45+
uruncJSONPath string
46+
guestType string
47+
guest types.Unikernel
48+
rootfsViewState *types.RootfsViewState
4849
}
4950

5051
// getMountInfo determines whether the provided path is a mount point
@@ -122,8 +123,6 @@ func getMountInfo(path string) (types.BlockDevParams, error) {
122123

123124
// extractUnikernelFromBlock moves unikernel binary, initrd and urunc.json
124125
// files from old rootfsPath to newRootfsPath
125-
// FIXME: This approach fills up /run with unikernel binaries, initrds and urunc.json
126-
// files for each unikernel we run
127126
func extractBootFiles(rootfsPath string, newRootfsPath string, unikernel string, uruncJSON string, initrd string) error {
128127
currentUnikernelPath := filepath.Join(rootfsPath, unikernel)
129128
targetUnikernelPath := filepath.Join(newRootfsPath, unikernel)
@@ -148,7 +147,6 @@ func extractBootFiles(rootfsPath string, newRootfsPath string, unikernel string,
148147
if err != nil {
149148
return fmt.Errorf("could not move %s to %s: %w", currentConfigPath, newRootfsPath, err)
150149
}
151-
152150
return nil
153151
}
154152

@@ -226,24 +224,36 @@ func getBlockVolumes(monRootfs string, mounts []specs.Mount, ukernel types.Unike
226224
}
227225

228226
func (b blockRootfs) preSetup() error {
227+
// Preserve main's propagation fix: consume boot artifacts and unmount the
228+
// container rootfs before prepareRoot() makes the mount tree private/slave.
229229
if b.mountedPath == "" {
230230
return nil
231231
}
232232

233-
err := copyMountfiles(b.mountedPath, b.mounts)
234-
if err != nil {
235-
return fmt.Errorf("failed to copy files from mount list: %w", err)
233+
useViewPath := b.rootfsViewState != nil
234+
if useViewPath {
235+
// Probe only; the real bind must happen after prepareRoot.
236+
useView, err := probeRootfsViewBootArtifacts(b.rootfsViewState, b.kernelPath, b.initrdPath, b.uruncJSONPath)
237+
if err != nil {
238+
return err
239+
}
240+
if !useView {
241+
useViewPath = false
242+
}
236243
}
237244

238-
// FIXME: This approach fills up /run with unikernel binaries and
239-
// urunc.json files for each unikernel instance we run
240-
err = extractBootFiles(b.mountedPath, b.monRootfs, b.kernelPath, b.uruncJSONPath, b.initrdPath)
241-
if err != nil {
242-
return fmt.Errorf("failed to extract boot files from rootfs: %w", err)
245+
if !useViewPath {
246+
err := extractBootFiles(b.mountedPath, b.monRootfs, b.kernelPath, b.uruncJSONPath, b.initrdPath)
247+
if err != nil {
248+
return fmt.Errorf("failed to extract boot files from rootfs: %w", err)
249+
}
243250
}
244251

245-
err = mount.Unmount(b.mountedPath)
246-
if err != nil {
252+
if err := copyMountfiles(b.mountedPath, b.mounts); err != nil {
253+
return fmt.Errorf("failed to copy files from mount list: %w", err)
254+
}
255+
256+
if err := mount.Unmount(b.mountedPath); err != nil {
247257
return fmt.Errorf("failed to unmount rootfs: %w", err)
248258
}
249259

@@ -262,10 +272,22 @@ func (b blockRootfs) postSetup() error {
262272
unix.MS_NOSUID|unix.MS_NOEXEC|unix.MS_STRICTATIME,
263273
"1777", tmpfsSizeForBlockRootfs)
264274
if err != nil {
265-
err = fmt.Errorf("failed to create tmpfs for monitor's execution environment: %w", err)
275+
return fmt.Errorf("failed to create tmpfs for monitor's execution environment: %w", err)
276+
}
277+
278+
if b.rootfsViewState == nil {
279+
return nil
266280
}
267281

268-
return err
282+
// Rootfs-view boot artifact binds must be created after prepareRoot()
283+
// has fixed the monitor rootfs propagation and self-bind. Keeping this in
284+
// postSetup() makes the ordering explicit while keeping the block-rootfs
285+
// specific setup inside the block rootfs implementation.
286+
if err := prepareRootfsViewBootBinds(b.rootfsViewState, b.monRootfs, b.kernelPath, b.initrdPath, b.uruncJSONPath); err != nil {
287+
return fmt.Errorf("boot artifact setup after prepareRoot failed: %w", err)
288+
}
289+
290+
return nil
269291
}
270292

271293
func (b blockRootfs) getBlockDevs() ([]types.BlockDevParams, error) {

pkg/unikontainers/unikontainers.go

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -306,11 +306,21 @@ func ChooseRootfs(bundle, specRoot string, annot map[string]string, cfg *UruncCo
306306
func (u *Unikontainer) Exec(metrics m.Writer) error {
307307
metrics.Capture(m.TS15)
308308

309+
// Reload annotations written by the shim after Create.
310+
spec, err := loadSpec(u.State.Bundle)
311+
if err != nil {
312+
return fmt.Errorf("reload bundle spec: %w", err)
313+
}
314+
if spec == nil || spec.Linux == nil {
315+
return fmt.Errorf("invalid OCI spec: linux section is required")
316+
}
317+
u.Spec = spec
318+
309319
// container Paths
310320
// Make sure paths are clean
311321
bundleDir := filepath.Clean(u.State.Bundle)
312322
rootfsDir := filepath.Clean(u.Spec.Root.Path)
313-
rootfsDir, err := resolveAgainstBase(bundleDir, rootfsDir)
323+
rootfsDir, err = resolveAgainstBase(bundleDir, rootfsDir)
314324
if err != nil {
315325
uniklog.Errorf("could not resolve rootfs directory %s: %v", rootfsDir, err)
316326
return err
@@ -461,16 +471,21 @@ func (u *Unikontainer) Exec(metrics m.Writer) error {
461471
var rfsBuilder rootfsBuilder
462472
switch rootfsParams.Type {
463473
case "block":
474+
view, err := LoadBundleRootfsView(bundleDir)
475+
if err != nil {
476+
return fmt.Errorf("could not load guest rootfs view: %w", err)
477+
}
464478
rfsBuilder = blockRootfs{
465-
mounts: u.Spec.Mounts,
466-
monRootfs: rootfsParams.MonRootfs,
467-
mountedPath: rootfsParams.MountedPath,
468-
path: rootfsParams.Path,
469-
kernelPath: unikernelPath,
470-
initrdPath: initrdPath,
471-
uruncJSONPath: uruncJSONFilename,
472-
guestType: unikernelType,
473-
guest: unikernel,
479+
mounts: u.Spec.Mounts,
480+
monRootfs: rootfsParams.MonRootfs,
481+
mountedPath: rootfsParams.MountedPath,
482+
path: rootfsParams.Path,
483+
kernelPath: unikernelPath,
484+
initrdPath: initrdPath,
485+
uruncJSONPath: uruncJSONFilename,
486+
guestType: unikernelType,
487+
guest: unikernel,
488+
rootfsViewState: view,
474489
}
475490
case "initrd":
476491
rfsBuilder = initrdRootfs{

0 commit comments

Comments
 (0)