From 5a56f4094800d1ad07b89d08365b70fcd613569a Mon Sep 17 00:00:00 2001 From: Hironori Shiina Date: Mon, 15 Nov 2021 16:54:50 -0500 Subject: Implement 'podman run --blkio-weight-device' `--blkio-weight-device` is not fully implemented and this causes an unexpected panic when specified because an entry is put into an uninitialized map at parsing. This fix implements the `--blkio-weight-device` and adds a system test. When creating a spec generator on a client, a major number and a minor number of a device cannot be set. So, these numbers are inspected on a server and set to a runtime spec. Signed-off-by: Hironori Shiina --- pkg/specgen/generate/oci.go | 8 ++++++ pkg/specgenutil/specgen.go | 17 +++++------ test/system/180-blkio.bats | 69 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 test/system/180-blkio.bats diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index 1b022b912..df5788099 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -329,6 +329,14 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access) } + for k, v := range s.WeightDevice { + statT := unix.Stat_t{} + if err := unix.Stat(k, &statT); err != nil { + return nil, errors.Wrapf(err, "failed to inspect '%s' in --blkio-weight-device", k) + } + g.AddLinuxResourcesBlockIOWeightDevice((int64(unix.Major(uint64(statT.Rdev)))), (int64(unix.Minor(uint64(statT.Rdev)))), *v.Weight) + } + BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), s.Mask, s.Unmask, &g) g.ClearProcessEnv() diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 7a572e730..637a6a8dd 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -85,7 +85,7 @@ func getIOLimits(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions) ( } if len(c.BlkIOWeightDevice) > 0 { - if err := parseWeightDevices(s, c.BlkIOWeightDevice); err != nil { + if s.WeightDevice, err = parseWeightDevices(c.BlkIOWeightDevice); err != nil { return nil, err } hasLimits = true @@ -791,29 +791,30 @@ func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, start return &hc, nil } -func parseWeightDevices(s *specgen.SpecGenerator, weightDevs []string) error { +func parseWeightDevices(weightDevs []string) (map[string]specs.LinuxWeightDevice, error) { + wd := make(map[string]specs.LinuxWeightDevice) for _, val := range weightDevs { split := strings.SplitN(val, ":", 2) if len(split) != 2 { - return fmt.Errorf("bad format: %s", val) + return nil, fmt.Errorf("bad format: %s", val) } if !strings.HasPrefix(split[0], "/dev/") { - return fmt.Errorf("bad format for device path: %s", val) + return nil, fmt.Errorf("bad format for device path: %s", val) } weight, err := strconv.ParseUint(split[1], 10, 0) if err != nil { - return fmt.Errorf("invalid weight for device: %s", val) + return nil, fmt.Errorf("invalid weight for device: %s", val) } if weight > 0 && (weight < 10 || weight > 1000) { - return fmt.Errorf("invalid weight for device: %s", val) + return nil, fmt.Errorf("invalid weight for device: %s", val) } w := uint16(weight) - s.WeightDevice[split[0]] = specs.LinuxWeightDevice{ + wd[split[0]] = specs.LinuxWeightDevice{ Weight: &w, LeafWeight: nil, } } - return nil + return wd, nil } func parseThrottleBPSDevices(bpsDevices []string) (map[string]specs.LinuxThrottleDevice, error) { diff --git a/test/system/180-blkio.bats b/test/system/180-blkio.bats new file mode 100644 index 000000000..68449681a --- /dev/null +++ b/test/system/180-blkio.bats @@ -0,0 +1,69 @@ +#!/usr/bin/env bats -*- bats -*- +# +# podman blkio-related tests +# + +load helpers + +function teardown() { + lofile=${PODMAN_TMPDIR}/disk.img + if [ -f ${lofile} ]; then + run_podman '?' rm -t 0 --all --force + + while read path dev; do + if [[ "$path" == "$lofile" ]]; then + losetup -d $dev + fi + done < <(losetup -l --noheadings --output BACK-FILE,NAME) + + rm ${lofile} + fi + basic_teardown +} + +@test "podman run --blkio-weight-device" { + + skip_if_rootless "cannot create devices in rootless mode" + + # create loopback device + lofile=${PODMAN_TMPDIR}/disk.img + fallocate -l 1k ${lofile} + losetup -f ${lofile} + + run losetup -l --noheadings --output BACK-FILE,NAME,MAJ:MIN + is "$output" ".\+" "Empty output from losetup" + + lodevice=$(awk "\$1 == \"$lofile\" { print \$2 }" <<<"$output") + lomajmin=$(awk "\$1 == \"$lofile\" { print \$3 }" <<<"$output") + + is "$lodevice" ".\+" "Could not determine device for $lofile" + is "$lomajmin" ".\+" "Could not determine major/minor for $lofile" + + # use bfq io scheduler + run grep -w bfq /sys/block/$(basename ${lodevice})/queue/scheduler + if [ $status -ne 0 ]; then + skip "BFQ scheduler is not supported on the system" + fi + echo bfq > /sys/block/$(basename ${lodevice})/queue/scheduler + + # run podman + if is_cgroupsv2; then + if [ ! -f /sys/fs/cgroup/system.slice/io.bfq.weight ]; then + skip "Kernel does not support BFQ IO scheduler" + fi + run_podman run --device ${lodevice}:${lodevice} --blkio-weight-device ${lodevice}:123 --rm $IMAGE \ + /bin/sh -c "cat /sys/fs/cgroup/\$(sed -e 's/0:://' < /proc/self/cgroup)/io.bfq.weight" + is "${lines[1]}" "${lomajmin}\s\+123" + else + if [ ! -f /sys/fs/cgroup/blkio/system.slice/blkio.bfq.weight_device ]; then + skip "Kernel does not support BFQ IO scheduler" + fi + if [ $(podman_runtime) = "crun" ]; then + # As of crun 1.2, crun doesn't support blkio.bfq.weight_device + skip "crun doesn't support blkio.bfq.weight_device" + fi + run_podman run --device ${lodevice}:${lodevice} --blkio-weight-device ${lodevice}:123 --rm $IMAGE \ + /bin/sh -c "cat /sys/fs/cgroup/blkio/blkio.bfq.weight_device" + is "${lines[1]}" "${lomajmin}\s\+123" + fi +} -- cgit v1.2.3-54-g00ecf