mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-10 21:29:01 +00:00
runtime: improve EROFS snapshotter support
To better support containerd 2.1 and later versions, remove the
hardcoded `layer.erofs` and instead parse `/proc/mounts` to obtain the
real mount source (and `/sys/block/loopX/loop/backing_file` if needed).
If the mount source doesn't end with `layer.erofs`, it should be marked
as unsupported, as it may be a filesystem meta file generated by later
containerd versions for the EROFS flattened filesystem feature.
Also check whether the filesystem type is `overlay` or not, since the
containerd mount manager [1] may change it after being introduced.
[1] https://github.com/containerd/containerd/issues/11303
Fixes: f63ec50ba3
("runtime: Add EROFS snapshotter with block device support")
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
This commit is contained in:
@@ -315,7 +315,7 @@ func checkAndMount(s *service, r *taskAPI.CreateTaskRequest) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if virtcontainers.HasErofsOptions(m.Options) {
|
if virtcontainers.IsErofsRootFS(virtcontainers.RootFs{Options: m.Options, Type: m.Type}) {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -130,7 +130,7 @@ func CreateSandbox(ctx context.Context, vci vc.VC, ociSpec specs.Spec, runtimeCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !rootFs.Mounted && len(sandboxConfig.Containers) == 1 {
|
if !rootFs.Mounted && len(sandboxConfig.Containers) == 1 {
|
||||||
if rootFs.Source != "" && !vc.HasOptionPrefix(rootFs.Options, vc.VirtualVolumePrefix) && !vc.HasErofsOptions(rootFs.Options) {
|
if rootFs.Source != "" && !vc.HasOptionPrefix(rootFs.Options, vc.VirtualVolumePrefix) && !vc.IsErofsRootFS(rootFs) {
|
||||||
realPath, err := ResolvePath(rootFs.Source)
|
realPath, err := ResolvePath(rootFs.Source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, vc.Process{}, err
|
return nil, vc.Process{}, err
|
||||||
@@ -244,7 +244,7 @@ func CreateContainer(ctx context.Context, sandbox vc.VCSandbox, ociSpec specs.Sp
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !rootFs.Mounted {
|
if !rootFs.Mounted {
|
||||||
if rootFs.Source != "" && !vc.IsNydusRootFSType(rootFs.Type) && !vc.HasErofsOptions(rootFs.Options) {
|
if rootFs.Source != "" && !vc.IsNydusRootFSType(rootFs.Type) && !vc.IsErofsRootFS(rootFs) {
|
||||||
realPath, err := ResolvePath(rootFs.Source)
|
realPath, err := ResolvePath(rootFs.Source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return vc.Process{}, err
|
return vc.Process{}, err
|
||||||
|
@@ -821,12 +821,48 @@ func (c *Container) createMounts(ctx context.Context) error {
|
|||||||
return c.createBlockDevices(ctx)
|
return c.createBlockDevices(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findMountSource(mnt string) (string, error) {
|
||||||
|
output, err := os.ReadFile("/proc/mounts")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// /proc/mounts has 6 fields per line, one mount per line, e.g.
|
||||||
|
// /dev/loop0 /var/lib/containerd/io.containerd.snapshotter.v1.erofs/snapshots/1/fs erofs ro,relatime,user_xattr,acl,cache_strategy=readaround 0 0
|
||||||
|
for _, line := range strings.Split(string(output), "\n") {
|
||||||
|
parts := strings.Split(line, " ")
|
||||||
|
if len(parts) == 6 {
|
||||||
|
switch parts[2] {
|
||||||
|
case "erofs":
|
||||||
|
if parts[1] == mnt {
|
||||||
|
return parts[0], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("erofs mount not found for %s", mnt)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Container) createErofsDevices() ([]config.DeviceInfo, error) {
|
func (c *Container) createErofsDevices() ([]config.DeviceInfo, error) {
|
||||||
var deviceInfos []config.DeviceInfo
|
var deviceInfos []config.DeviceInfo
|
||||||
if HasErofsOptions(c.rootFs.Options) {
|
if IsErofsRootFS(c.rootFs) {
|
||||||
parsedOptions := parseRootFsOptions(c.rootFs.Options)
|
lowerdirs := parseErofsRootFsOptions(c.rootFs.Options)
|
||||||
for _, path := range parsedOptions {
|
for _, path := range lowerdirs {
|
||||||
di, err := c.createDeviceInfo(path+"/layer.erofs", path+"/layer.erofs", true, true)
|
s, err := findMountSource(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(s, "/dev/loop") {
|
||||||
|
b, err := os.ReadFile(fmt.Sprintf("/sys/block/loop%s/loop/backing_file", strings.TrimPrefix(s, "/dev/loop")))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
s = strings.TrimSuffix(string(b), "\n")
|
||||||
|
}
|
||||||
|
if filepath.Base(s) != "layer.erofs" {
|
||||||
|
return nil, fmt.Errorf("unsupported mount source %s for %s", s, path)
|
||||||
|
}
|
||||||
|
di, err := c.createDeviceInfo(s, s, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1076,7 +1112,7 @@ func (c *Container) create(ctx context.Context) (err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if c.checkBlockDeviceSupport(ctx) && !IsNydusRootFSType(c.rootFs.Type) && !HasErofsOptions(c.rootFs.Options) {
|
if c.checkBlockDeviceSupport(ctx) && !IsNydusRootFSType(c.rootFs.Type) && !IsErofsRootFS(c.rootFs) {
|
||||||
// If the rootfs is backed by a block device, go ahead and hotplug it to the guest
|
// If the rootfs is backed by a block device, go ahead and hotplug it to the guest
|
||||||
if err = c.hotplugDrive(ctx); err != nil {
|
if err = c.hotplugDrive(ctx); err != nil {
|
||||||
return
|
return
|
||||||
|
@@ -626,7 +626,7 @@ func (f *FilesystemShare) ShareRootFilesystem(ctx context.Context, c *Container)
|
|||||||
return f.shareRootFilesystemWithNydus(ctx, c)
|
return f.shareRootFilesystemWithNydus(ctx, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
if HasErofsOptions(c.rootFs.Options) {
|
if IsErofsRootFS(c.rootFs) {
|
||||||
return f.shareRootFilesystemWithErofs(ctx, c)
|
return f.shareRootFilesystemWithErofs(ctx, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -2703,9 +2703,13 @@ func IsNydusRootFSType(s string) bool {
|
|||||||
return strings.HasPrefix(path.Base(s), "nydus-overlayfs")
|
return strings.HasPrefix(path.Base(s), "nydus-overlayfs")
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasErofsOptions checks if any of the options contain io.containerd.snapshotter.v1.erofs path
|
// IsErofsRootFS checks if any of the options contain io.containerd.snapshotter.v1.erofs path
|
||||||
func HasErofsOptions(options []string) bool {
|
func IsErofsRootFS(root RootFs) bool {
|
||||||
for _, opt := range options {
|
// TODO: support containerd mount manager: https://github.com/containerd/containerd/issues/11303
|
||||||
|
if root.Type != "overlay" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, opt := range root.Options {
|
||||||
if strings.Contains(opt, "io.containerd.snapshotter.v1.erofs") {
|
if strings.Contains(opt, "io.containerd.snapshotter.v1.erofs") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -2713,21 +2717,15 @@ func HasErofsOptions(options []string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseRootFsOptions(options []string) []string {
|
func parseErofsRootFsOptions(options []string) []string {
|
||||||
lowerdirs := []string{}
|
lowerdirs := []string{}
|
||||||
|
|
||||||
for _, opt := range options {
|
for _, opt := range options {
|
||||||
if strings.HasPrefix(opt, "lowerdir=") {
|
if strings.HasPrefix(opt, "lowerdir=") {
|
||||||
lowerdirValue := strings.TrimPrefix(opt, "lowerdir=")
|
lowerdirValue := strings.TrimPrefix(opt, "lowerdir=")
|
||||||
|
|
||||||
paths := strings.Split(lowerdirValue, ":")
|
lowerdirs = append(lowerdirs, strings.Split(lowerdirValue, ":")...)
|
||||||
|
|
||||||
for _, path := range paths {
|
|
||||||
path = strings.TrimSuffix(path, "/fs")
|
|
||||||
lowerdirs = append(lowerdirs, path)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return lowerdirs
|
return lowerdirs
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user