github.com/allencloud/containerd@v0.2.5/runtime/container_linux.go (about) 1 package runtime 2 3 import ( 4 "bufio" 5 "bytes" 6 "encoding/json" 7 "fmt" 8 "os" 9 "os/exec" 10 "path/filepath" 11 "strings" 12 "syscall" 13 14 "github.com/docker/containerd/specs" 15 ocs "github.com/opencontainers/runtime-spec/specs-go" 16 ) 17 18 func findCgroupMountpointAndRoot(pid int, subsystem string) (string, string, error) { 19 f, err := os.Open(fmt.Sprintf("/proc/%d/mountinfo", pid)) 20 if err != nil { 21 return "", "", err 22 } 23 defer f.Close() 24 25 scanner := bufio.NewScanner(f) 26 for scanner.Scan() { 27 txt := scanner.Text() 28 fields := strings.Split(txt, " ") 29 for _, opt := range strings.Split(fields[len(fields)-1], ",") { 30 if opt == subsystem { 31 return fields[4], fields[3], nil 32 } 33 } 34 } 35 if err := scanner.Err(); err != nil { 36 return "", "", err 37 } 38 39 return "", "", fmt.Errorf("cgroup path for %s not found", subsystem) 40 } 41 42 func parseCgroupFile(path string) (map[string]string, error) { 43 f, err := os.Open(path) 44 if err != nil { 45 return nil, err 46 } 47 defer f.Close() 48 49 s := bufio.NewScanner(f) 50 cgroups := make(map[string]string) 51 52 for s.Scan() { 53 if err := s.Err(); err != nil { 54 return nil, err 55 } 56 57 text := s.Text() 58 parts := strings.Split(text, ":") 59 60 for _, subs := range strings.Split(parts[1], ",") { 61 cgroups[subs] = parts[2] 62 } 63 } 64 return cgroups, nil 65 } 66 67 func (c *container) OOM() (OOM, error) { 68 p := c.processes[InitProcessID] 69 if p == nil { 70 return nil, fmt.Errorf("no init process found") 71 } 72 73 mountpoint, hostRoot, err := findCgroupMountpointAndRoot(os.Getpid(), "memory") 74 if err != nil { 75 return nil, err 76 } 77 78 cgroups, err := parseCgroupFile(fmt.Sprintf("/proc/%d/cgroup", p.pid)) 79 if err != nil { 80 return nil, err 81 } 82 83 root, ok := cgroups["memory"] 84 if !ok { 85 return nil, fmt.Errorf("no memory cgroup for container %s", c.ID()) 86 } 87 88 // Take care of the case were we're running inside a container 89 // ourself 90 root = strings.TrimPrefix(root, hostRoot) 91 92 return c.getMemeoryEventFD(filepath.Join(mountpoint, root)) 93 } 94 95 func u64Ptr(i uint64) *uint64 { return &i } 96 97 func (c *container) UpdateResources(r *Resource) error { 98 sr := ocs.Resources{ 99 Memory: &ocs.Memory{ 100 Limit: u64Ptr(uint64(r.Memory)), 101 Reservation: u64Ptr(uint64(r.MemoryReservation)), 102 Swap: u64Ptr(uint64(r.MemorySwap)), 103 Kernel: u64Ptr(uint64(r.KernelMemory)), 104 KernelTCP: u64Ptr(uint64(r.KernelTCPMemory)), 105 }, 106 CPU: &ocs.CPU{ 107 Shares: u64Ptr(uint64(r.CPUShares)), 108 Quota: u64Ptr(uint64(r.CPUQuota)), 109 Period: u64Ptr(uint64(r.CPUPeriod)), 110 Cpus: &r.CpusetCpus, 111 Mems: &r.CpusetMems, 112 }, 113 BlockIO: &ocs.BlockIO{ 114 Weight: &r.BlkioWeight, 115 }, 116 } 117 118 srStr := bytes.NewBuffer(nil) 119 if err := json.NewEncoder(srStr).Encode(&sr); err != nil { 120 return err 121 } 122 123 args := c.runtimeArgs 124 args = append(args, "update", "-r", "-", c.id) 125 cmd := exec.Command(c.runtime, args...) 126 cmd.Stdin = srStr 127 b, err := cmd.CombinedOutput() 128 if err != nil { 129 return fmt.Errorf(string(b)) 130 } 131 return nil 132 } 133 134 func getRootIDs(s *specs.Spec) (int, int, error) { 135 if s == nil { 136 return 0, 0, nil 137 } 138 var hasUserns bool 139 for _, ns := range s.Linux.Namespaces { 140 if ns.Type == ocs.UserNamespace { 141 hasUserns = true 142 break 143 } 144 } 145 if !hasUserns { 146 return 0, 0, nil 147 } 148 uid := hostIDFromMap(0, s.Linux.UIDMappings) 149 gid := hostIDFromMap(0, s.Linux.GIDMappings) 150 return uid, gid, nil 151 } 152 153 func (c *container) getMemeoryEventFD(root string) (*oom, error) { 154 f, err := os.Open(filepath.Join(root, "memory.oom_control")) 155 if err != nil { 156 return nil, err 157 } 158 fd, _, serr := syscall.RawSyscall(syscall.SYS_EVENTFD2, 0, syscall.FD_CLOEXEC, 0) 159 if serr != 0 { 160 f.Close() 161 return nil, serr 162 } 163 if err := c.writeEventFD(root, int(f.Fd()), int(fd)); err != nil { 164 syscall.Close(int(fd)) 165 f.Close() 166 return nil, err 167 } 168 return &oom{ 169 root: root, 170 id: c.id, 171 eventfd: int(fd), 172 control: f, 173 }, nil 174 }