github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/pkg/sentry/control/cgroups.go (about) 1 // Copyright 2022 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package control 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/MerlinKodo/gvisor/pkg/context" 22 "github.com/MerlinKodo/gvisor/pkg/sentry/kernel" 23 ) 24 25 // Cgroups contains the state for cgroupfs related control commands. 26 type Cgroups struct { 27 Kernel *kernel.Kernel 28 } 29 30 func (c *Cgroups) findCgroup(ctx context.Context, file CgroupControlFile) (kernel.Cgroup, error) { 31 ctl, err := file.controller() 32 if err != nil { 33 return kernel.Cgroup{}, err 34 } 35 return c.Kernel.CgroupRegistry().FindCgroup(ctx, ctl, file.Path) 36 } 37 38 // CgroupControlFile identifies a specific control file within a 39 // specific cgroup, for the hierarchy with a given controller. 40 type CgroupControlFile struct { 41 Controller string `json:"controller"` 42 Path string `json:"path"` 43 Name string `json:"name"` 44 } 45 46 func (f *CgroupControlFile) controller() (kernel.CgroupControllerType, error) { 47 return kernel.ParseCgroupController(f.Controller) 48 } 49 50 // CgroupsResult represents the result of a cgroup operation. 51 type CgroupsResult struct { 52 Data string `json:"value"` 53 IsError bool `json:"is_error"` 54 } 55 56 // AsError interprets the result as an error. 57 func (r *CgroupsResult) AsError() error { 58 if r.IsError { 59 return fmt.Errorf(r.Data) 60 } 61 return nil 62 } 63 64 // Unpack splits CgroupsResult into a (value, error) tuple. 65 func (r *CgroupsResult) Unpack() (string, error) { 66 if r.IsError { 67 return "", fmt.Errorf(r.Data) 68 } 69 return r.Data, nil 70 } 71 72 func newValue(val string) CgroupsResult { 73 return CgroupsResult{ 74 Data: strings.TrimSpace(val), 75 } 76 } 77 78 func newError(err error) CgroupsResult { 79 return CgroupsResult{ 80 Data: err.Error(), 81 IsError: true, 82 } 83 } 84 85 // CgroupsResults represents the list of results for a batch command. 86 type CgroupsResults struct { 87 Results []CgroupsResult `json:"results"` 88 } 89 90 func (o *CgroupsResults) appendValue(val string) { 91 o.Results = append(o.Results, newValue(val)) 92 } 93 94 func (o *CgroupsResults) appendError(err error) { 95 o.Results = append(o.Results, newError(err)) 96 } 97 98 // CgroupsReadArg represents the arguments for a single read command. 99 type CgroupsReadArg struct { 100 File CgroupControlFile `json:"file"` 101 } 102 103 // CgroupsReadArgs represents the list of arguments for a batched read command. 104 type CgroupsReadArgs struct { 105 Args []CgroupsReadArg `json:"args"` 106 } 107 108 // ReadControlFiles is an RPC stub for batch-reading cgroupfs control files. 109 func (c *Cgroups) ReadControlFiles(args *CgroupsReadArgs, out *CgroupsResults) error { 110 ctx := c.Kernel.SupervisorContext() 111 for _, arg := range args.Args { 112 cg, err := c.findCgroup(ctx, arg.File) 113 if err != nil { 114 out.appendError(err) 115 continue 116 } 117 118 val, err := cg.ReadControl(ctx, arg.File.Name) 119 if err != nil { 120 out.appendError(err) 121 } else { 122 out.appendValue(val) 123 } 124 } 125 126 return nil 127 } 128 129 // CgroupsWriteArg represents the arguments for a single write command. 130 type CgroupsWriteArg struct { 131 File CgroupControlFile `json:"file"` 132 Value string `json:"value"` 133 } 134 135 // CgroupsWriteArgs represents the lust of arguments for a batched write command. 136 type CgroupsWriteArgs struct { 137 Args []CgroupsWriteArg `json:"args"` 138 } 139 140 // WriteControlFiles is an RPC stub for batch-writing cgroupfs control files. 141 func (c *Cgroups) WriteControlFiles(args *CgroupsWriteArgs, out *CgroupsResults) error { 142 ctx := c.Kernel.SupervisorContext() 143 144 for _, arg := range args.Args { 145 cg, err := c.findCgroup(ctx, arg.File) 146 if err != nil { 147 out.appendError(err) 148 continue 149 } 150 151 err = cg.WriteControl(ctx, arg.File.Name, arg.Value) 152 if err != nil { 153 out.appendError(err) 154 } else { 155 out.appendValue("") 156 } 157 } 158 return nil 159 }