Skip to content

Commit

Permalink
libcontainer/cgroups/fs/blkio: support BFQ weight[_device]
Browse files Browse the repository at this point in the history
- Update the blkio cgroup to support the BFQ I/O Scheduler, that has
  replaced CFQ in the Linux kernel.
- BFQ is controlled through blkio.bfq.weight[_device] instead of
  CFQ's blkio.weight[_device] in cgroups v1.
- BFQ does not support blkio.leaf_weight[_device], so that behavior
  remains untouched.
- Do not change behavior on legacy CFQ systems.
- Enable using blkio weights on BFQ systems.

Signed-off-by: Antti Kervinen <[email protected]>
  • Loading branch information
askervin committed Jun 11, 2021
1 parent 4d6b929 commit 6339d8a
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 51 deletions.
25 changes: 22 additions & 3 deletions libcontainer/cgroups/fs/blkio.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"bufio"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"

Expand All @@ -14,7 +15,10 @@ import (
"github.com/opencontainers/runc/libcontainer/configs"
)

type BlkioGroup struct{}
type BlkioGroup struct {
weightFilename string
weightDeviceFilename string
}

func (s *BlkioGroup) Name() string {
return "blkio"
Expand All @@ -25,8 +29,9 @@ func (s *BlkioGroup) Apply(path string, d *cgroupData) error {
}

func (s *BlkioGroup) Set(path string, r *configs.Resources) error {
s.detectWeightFilenames(path)
if r.BlkioWeight != 0 {
if err := fscommon.WriteFile(path, "blkio.weight", strconv.FormatUint(uint64(r.BlkioWeight), 10)); err != nil {
if err := fscommon.WriteFile(path, s.weightFilename, strconv.FormatUint(uint64(r.BlkioWeight), 10)); err != nil {
return err
}
}
Expand All @@ -37,7 +42,7 @@ func (s *BlkioGroup) Set(path string, r *configs.Resources) error {
}
}
for _, wd := range r.BlkioWeightDevice {
if err := fscommon.WriteFile(path, "blkio.weight_device", wd.WeightString()); err != nil {
if err := fscommon.WriteFile(path, s.weightDeviceFilename, wd.WeightString()); err != nil {
return err
}
if err := fscommon.WriteFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil {
Expand Down Expand Up @@ -287,3 +292,17 @@ func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
}
return nil
}

func (s *BlkioGroup) detectWeightFilenames(path string) {
if s.weightFilename != "" {
// Already detected.
return
}
if cgroups.PathExists(filepath.Join(path, "blkio.weight")) {
s.weightFilename = "blkio.weight"
s.weightDeviceFilename = "blkio.weight_device"
} else {
s.weightFilename = "blkio.bfq.weight"
s.weightDeviceFilename = "blkio.bfq.weight_device"
}
}
118 changes: 70 additions & 48 deletions libcontainer/cgroups/fs/blkio_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,62 +171,80 @@ func appendBlkioStatEntry(blkioStatEntries *[]cgroups.BlkioStatEntry, major, min
}

func TestBlkioSetWeight(t *testing.T) {
helper := NewCgroupTestUtil("blkio", t)
defer helper.cleanup()

const (
weightBefore = 100
weightAfter = 200
)

helper.writeFileContents(map[string]string{
"blkio.weight": strconv.Itoa(weightBefore),
})

helper.CgroupData.config.Resources.BlkioWeight = weightAfter
blkio := &BlkioGroup{}
if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config.Resources); err != nil {
t.Fatal(err)
}

value, err := fscommon.GetCgroupParamUint(helper.CgroupPath, "blkio.weight")
if err != nil {
t.Fatalf("Failed to parse blkio.weight - %s", err)
}

if value != weightAfter {
t.Fatal("Got the wrong value, set blkio.weight failed.")
for _, legacyIOScheduler := range []bool{false, true} {
// Populate cgroup
helper := NewCgroupTestUtil("blkio", t)
defer helper.cleanup()
weightFilename := "blkio.bfq.weight"
if legacyIOScheduler {
weightFilename = "blkio.weight"
}
helper.writeFileContents(map[string]string{
weightFilename: strconv.Itoa(weightBefore),
})
// Apply new configuration
helper.CgroupData.config.Resources.BlkioWeight = weightAfter
blkio := &BlkioGroup{}
if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config.Resources); err != nil {
t.Fatal(err)
}
// Verify results
if weightFilename != blkio.weightFilename {
t.Fatalf("weight filename detection failed: expected %q, detected %q", weightFilename, blkio.weightFilename)
}
value, err := fscommon.GetCgroupParamUint(helper.CgroupPath, weightFilename)
if err != nil {
t.Fatal(err)
}
if value != weightAfter {
t.Fatalf("Got the wrong value, set %s failed.", weightFilename)
}
}
}

func TestBlkioSetWeightDevice(t *testing.T) {
helper := NewCgroupTestUtil("blkio", t)
defer helper.cleanup()

const (
weightDeviceBefore = "8:0 400"
)

wd := configs.NewWeightDevice(8, 0, 500, 0)
weightDeviceAfter := wd.WeightString()

helper.writeFileContents(map[string]string{
"blkio.weight_device": weightDeviceBefore,
})

helper.CgroupData.config.Resources.BlkioWeightDevice = []*configs.WeightDevice{wd}
blkio := &BlkioGroup{}
if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config.Resources); err != nil {
t.Fatal(err)
}

value, err := fscommon.GetCgroupParamString(helper.CgroupPath, "blkio.weight_device")
if err != nil {
t.Fatalf("Failed to parse blkio.weight_device - %s", err)
}

if value != weightDeviceAfter {
t.Fatal("Got the wrong value, set blkio.weight_device failed.")
for _, legacyIOScheduler := range []bool{false, true} {
// Populate cgroup
helper := NewCgroupTestUtil("blkio", t)
defer helper.cleanup()
weightFilename := "blkio.bfq.weight"
weightDeviceFilename := "blkio.bfq.weight_device"
if legacyIOScheduler {
weightFilename = "blkio.weight"
weightDeviceFilename = "blkio.weight_device"
}
helper.writeFileContents(map[string]string{
weightFilename: "",
weightDeviceFilename: weightDeviceBefore,
})
// Apply new configuration
wd := configs.NewWeightDevice(8, 0, 500, 0)
weightDeviceAfter := wd.WeightString()
helper.CgroupData.config.Resources.BlkioWeightDevice = []*configs.WeightDevice{wd}
blkio := &BlkioGroup{}
if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config.Resources); err != nil {
t.Fatal(err)
}
// Verify results
if weightDeviceFilename != blkio.weightDeviceFilename {
t.Fatalf("weight_device filename detection failed: expected %q, detected %q", weightDeviceFilename, blkio.weightDeviceFilename)
}
value, err := fscommon.GetCgroupParamString(helper.CgroupPath, weightDeviceFilename)
if err != nil {
t.Fatal(err)
}
if value != weightDeviceAfter {
t.Fatalf("Got the wrong value, set %s failed.", weightDeviceFilename)
}
}
}

Expand All @@ -247,23 +265,27 @@ func TestBlkioSetMultipleWeightDevice(t *testing.T) {
// is present will suffice for the test to ensure multiple writes are done.
weightDeviceAfter := wd2.WeightString()

blkio := &BlkioGroup{}
blkio.detectWeightFilenames(helper.CgroupPath)
if blkio.weightDeviceFilename != "blkio.bfq.weight_device" {
t.Fatalf("when blkio controller is unavailable, expected to use \"blkio.bfq.weight_device\", tried to use %q", blkio.weightDeviceFilename)
}
helper.writeFileContents(map[string]string{
"blkio.weight_device": weightDeviceBefore,
blkio.weightDeviceFilename: weightDeviceBefore,
})

helper.CgroupData.config.Resources.BlkioWeightDevice = []*configs.WeightDevice{wd1, wd2}
blkio := &BlkioGroup{}
if err := blkio.Set(helper.CgroupPath, helper.CgroupData.config.Resources); err != nil {
t.Fatal(err)
}

value, err := fscommon.GetCgroupParamString(helper.CgroupPath, "blkio.weight_device")
value, err := fscommon.GetCgroupParamString(helper.CgroupPath, blkio.weightDeviceFilename)
if err != nil {
t.Fatalf("Failed to parse blkio.weight_device - %s", err)
t.Fatal(err)
}

if value != weightDeviceAfter {
t.Fatal("Got the wrong value, set blkio.weight_device failed.")
t.Fatalf("Got the wrong value, set %s failed.", blkio.weightDeviceFilename)
}
}

Expand Down

0 comments on commit 6339d8a

Please sign in to comment.