github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/cgroups/blkio.go (about)

     1  package cgroups
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"strconv"
     9  	"strings"
    10  
    11  	spec "github.com/opencontainers/runtime-spec/specs-go"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  type blkioHandler struct {
    16  }
    17  
    18  func getBlkioHandler() *blkioHandler {
    19  	return &blkioHandler{}
    20  }
    21  
    22  // Apply set the specified constraints
    23  func (c *blkioHandler) Apply(ctr *CgroupControl, res *spec.LinuxResources) error {
    24  	if res.BlockIO == nil {
    25  		return nil
    26  	}
    27  	return fmt.Errorf("blkio apply function not implemented yet")
    28  }
    29  
    30  // Create the cgroup
    31  func (c *blkioHandler) Create(ctr *CgroupControl) (bool, error) {
    32  	if ctr.cgroup2 {
    33  		return false, nil
    34  	}
    35  	return ctr.createCgroupDirectory(Blkio)
    36  }
    37  
    38  // Destroy the cgroup
    39  func (c *blkioHandler) Destroy(ctr *CgroupControl) error {
    40  	return rmDirRecursively(ctr.getCgroupv1Path(Blkio))
    41  }
    42  
    43  // Stat fills a metrics structure with usage stats for the controller
    44  func (c *blkioHandler) Stat(ctr *CgroupControl, m *Metrics) error {
    45  	var ioServiceBytesRecursive []BlkIOEntry
    46  
    47  	if ctr.cgroup2 {
    48  		// more details on the io.stat file format:X https://facebookmicrosites.github.io/cgroup2/docs/io-controller.html
    49  		values, err := readCgroup2MapFile(ctr, "io.stat")
    50  		if err != nil {
    51  			return err
    52  		}
    53  		for k, v := range values {
    54  			d := strings.Split(k, ":")
    55  			if len(d) != 2 {
    56  				continue
    57  			}
    58  			minor, err := strconv.ParseUint(d[0], 10, 0)
    59  			if err != nil {
    60  				return err
    61  			}
    62  			major, err := strconv.ParseUint(d[1], 10, 0)
    63  			if err != nil {
    64  				return err
    65  			}
    66  
    67  			for _, item := range v {
    68  				d := strings.Split(item, "=")
    69  				if len(d) != 2 {
    70  					continue
    71  				}
    72  				op := d[0]
    73  
    74  				// Accommodate the cgroup v1 naming
    75  				switch op {
    76  				case "rbytes":
    77  					op = "read"
    78  				case "wbytes":
    79  					op = "write"
    80  				}
    81  
    82  				value, err := strconv.ParseUint(d[1], 10, 0)
    83  				if err != nil {
    84  					return err
    85  				}
    86  
    87  				entry := BlkIOEntry{
    88  					Op:    op,
    89  					Major: major,
    90  					Minor: minor,
    91  					Value: value,
    92  				}
    93  				ioServiceBytesRecursive = append(ioServiceBytesRecursive, entry)
    94  			}
    95  		}
    96  	} else {
    97  		BlkioRoot := ctr.getCgroupv1Path(Blkio)
    98  
    99  		p := filepath.Join(BlkioRoot, "blkio.throttle.io_service_bytes_recursive")
   100  		f, err := os.Open(p)
   101  		if err != nil {
   102  			if os.IsNotExist(err) {
   103  				return nil
   104  			}
   105  			return errors.Wrapf(err, "open %s", p)
   106  		}
   107  		defer f.Close()
   108  
   109  		scanner := bufio.NewScanner(f)
   110  		for scanner.Scan() {
   111  			line := scanner.Text()
   112  			parts := strings.Fields(line)
   113  			if len(parts) < 3 {
   114  				continue
   115  			}
   116  			d := strings.Split(parts[0], ":")
   117  			if len(d) != 2 {
   118  				continue
   119  			}
   120  			minor, err := strconv.ParseUint(d[0], 10, 0)
   121  			if err != nil {
   122  				return err
   123  			}
   124  			major, err := strconv.ParseUint(d[1], 10, 0)
   125  			if err != nil {
   126  				return err
   127  			}
   128  
   129  			op := parts[1]
   130  
   131  			value, err := strconv.ParseUint(parts[2], 10, 0)
   132  			if err != nil {
   133  				return err
   134  			}
   135  			entry := BlkIOEntry{
   136  				Op:    op,
   137  				Major: major,
   138  				Minor: minor,
   139  				Value: value,
   140  			}
   141  			ioServiceBytesRecursive = append(ioServiceBytesRecursive, entry)
   142  		}
   143  		if err := scanner.Err(); err != nil {
   144  			return errors.Wrapf(err, "parse %s", p)
   145  		}
   146  	}
   147  	m.Blkio = BlkioMetrics{IoServiceBytesRecursive: ioServiceBytesRecursive}
   148  	return nil
   149  }