mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-09-08 12:18:57 +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:
@@ -821,12 +821,48 @@ func (c *Container) createMounts(ctx context.Context) error {
|
||||
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) {
|
||||
var deviceInfos []config.DeviceInfo
|
||||
if HasErofsOptions(c.rootFs.Options) {
|
||||
parsedOptions := parseRootFsOptions(c.rootFs.Options)
|
||||
for _, path := range parsedOptions {
|
||||
di, err := c.createDeviceInfo(path+"/layer.erofs", path+"/layer.erofs", true, true)
|
||||
if IsErofsRootFS(c.rootFs) {
|
||||
lowerdirs := parseErofsRootFsOptions(c.rootFs.Options)
|
||||
for _, path := range lowerdirs {
|
||||
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 {
|
||||
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 err = c.hotplugDrive(ctx); err != nil {
|
||||
return
|
||||
|
@@ -626,7 +626,7 @@ func (f *FilesystemShare) ShareRootFilesystem(ctx context.Context, c *Container)
|
||||
return f.shareRootFilesystemWithNydus(ctx, c)
|
||||
}
|
||||
|
||||
if HasErofsOptions(c.rootFs.Options) {
|
||||
if IsErofsRootFS(c.rootFs) {
|
||||
return f.shareRootFilesystemWithErofs(ctx, c)
|
||||
}
|
||||
|
||||
|
@@ -2703,9 +2703,13 @@ func IsNydusRootFSType(s string) bool {
|
||||
return strings.HasPrefix(path.Base(s), "nydus-overlayfs")
|
||||
}
|
||||
|
||||
// HasErofsOptions checks if any of the options contain io.containerd.snapshotter.v1.erofs path
|
||||
func HasErofsOptions(options []string) bool {
|
||||
for _, opt := range options {
|
||||
// IsErofsRootFS checks if any of the options contain io.containerd.snapshotter.v1.erofs path
|
||||
func IsErofsRootFS(root RootFs) bool {
|
||||
// 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") {
|
||||
return true
|
||||
}
|
||||
@@ -2713,21 +2717,15 @@ func HasErofsOptions(options []string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func parseRootFsOptions(options []string) []string {
|
||||
func parseErofsRootFsOptions(options []string) []string {
|
||||
lowerdirs := []string{}
|
||||
|
||||
for _, opt := range options {
|
||||
if strings.HasPrefix(opt, "lowerdir=") {
|
||||
lowerdirValue := strings.TrimPrefix(opt, "lowerdir=")
|
||||
|
||||
paths := strings.Split(lowerdirValue, ":")
|
||||
|
||||
for _, path := range paths {
|
||||
path = strings.TrimSuffix(path, "/fs")
|
||||
lowerdirs = append(lowerdirs, path)
|
||||
}
|
||||
lowerdirs = append(lowerdirs, strings.Split(lowerdirValue, ":")...)
|
||||
}
|
||||
}
|
||||
|
||||
return lowerdirs
|
||||
}
|
||||
|
Reference in New Issue
Block a user