xref: /unit/src/nxt_cgroup.c (revision 2259:be0239db0ed9)
1 /*
2  * Copyright (C) Andrew Clayton
3  * Copyright (C) F5, Inc.
4  */
5 
6 #include <nxt_main.h>
7 
8 #include <nxt_cgroup.h>
9 
10 
11 static int nxt_mk_cgpath_relative(nxt_task_t *task, const char *dir,
12     char *cgpath);
13 static nxt_int_t nxt_mk_cgpath(nxt_task_t *task, const char *dir,
14     char *cgpath);
15 
16 
17 nxt_int_t
nxt_cgroup_proc_add(nxt_task_t * task,nxt_process_t * process)18 nxt_cgroup_proc_add(nxt_task_t *task, nxt_process_t *process)
19 {
20     int        len;
21     char       cgprocs[NXT_MAX_PATH_LEN];
22     FILE       *fp;
23     nxt_int_t  ret;
24 
25     if (task->thread->runtime->type != NXT_PROCESS_MAIN
26         || nxt_process_type(process) != NXT_PROCESS_PROTOTYPE
27         || process->isolation.cgroup.path == NULL)
28     {
29         return NXT_OK;
30     }
31 
32     ret = nxt_mk_cgpath(task, process->isolation.cgroup.path, cgprocs);
33     if (nxt_slow_path(ret == NXT_ERROR)) {
34         return NXT_ERROR;
35     }
36 
37     ret = nxt_fs_mkdir_all((const u_char *) cgprocs, 0777);
38     if (nxt_slow_path(ret == NXT_ERROR)) {
39         return NXT_ERROR;
40     }
41 
42     len = strlen(cgprocs);
43 
44     len = snprintf(cgprocs + len, NXT_MAX_PATH_LEN - len, "/cgroup.procs");
45     if (nxt_slow_path(len >= NXT_MAX_PATH_LEN - len)) {
46         nxt_errno = ENAMETOOLONG;
47         return NXT_ERROR;
48     }
49 
50     fp = nxt_file_fopen(task, cgprocs, "we");
51     if (nxt_slow_path(fp == NULL)) {
52         return NXT_ERROR;
53     }
54 
55     setvbuf(fp, NULL, _IONBF, 0);
56     len = fprintf(fp, "%d\n", process->pid);
57     nxt_file_fclose(task, fp);
58 
59     if (nxt_slow_path(len < 0)) {
60         return NXT_ERROR;
61     }
62 
63     return NXT_OK;
64 }
65 
66 
67 void
nxt_cgroup_cleanup(nxt_task_t * task,const nxt_process_t * process)68 nxt_cgroup_cleanup(nxt_task_t *task, const nxt_process_t *process)
69 {
70     char       *ptr;
71     char       cgroot[NXT_MAX_PATH_LEN], cgpath[NXT_MAX_PATH_LEN];
72     nxt_int_t  ret;
73 
74     ret = nxt_mk_cgpath(task, "", cgroot);
75     if (nxt_slow_path(ret == NXT_ERROR)) {
76         return;
77     }
78 
79     ret = nxt_mk_cgpath(task, process->isolation.cgroup.path, cgpath);
80     if (nxt_slow_path(ret == NXT_ERROR)) {
81         return;
82     }
83 
84     while (*cgpath != '\0' && strcmp(cgroot, cgpath) != 0) {
85         rmdir(cgpath);
86         ptr = strrchr(cgpath, '/');
87         *ptr = '\0';
88     }
89 }
90 
91 
92 static int
nxt_mk_cgpath_relative(nxt_task_t * task,const char * dir,char * cgpath)93 nxt_mk_cgpath_relative(nxt_task_t *task, const char *dir, char *cgpath)
94 {
95     int         i, len;
96     char        *buf, *ptr;
97     FILE        *fp;
98     size_t      size;
99     ssize_t     nread;
100     nxt_bool_t  found;
101 
102     fp = nxt_file_fopen(task, "/proc/self/cgroup", "re");
103     if (nxt_slow_path(fp == NULL)) {
104         return -1;
105     }
106 
107     len = -1;
108     buf = NULL;
109     found = 0;
110     while ((nread = getline(&buf, &size, fp)) != -1) {
111         if (strncmp(buf, "0::", 3) == 0) {
112             found = 1;
113             break;
114         }
115     }
116 
117     nxt_file_fclose(task, fp);
118 
119     if (!found) {
120         nxt_errno = ENODATA;
121         goto out_free_buf;
122     }
123 
124     buf[nread - 1] = '\0';  /* lose the trailing '\n' */
125     ptr = buf;
126     for (i = 0; i < 2; i++) {
127         ptr = strchr(ptr, ':');
128         if (ptr == NULL) {
129             nxt_errno = ENODATA;
130             goto out_free_buf;
131         }
132 
133         ptr++;
134     }
135 
136     len = snprintf(cgpath, NXT_MAX_PATH_LEN, NXT_CGROUP_ROOT "%s/%s",
137                    ptr, dir);
138 
139 out_free_buf:
140 
141     nxt_free(buf);
142 
143     return len;
144 }
145 
146 
147 static nxt_int_t
nxt_mk_cgpath(nxt_task_t * task,const char * dir,char * cgpath)148 nxt_mk_cgpath(nxt_task_t *task, const char *dir, char *cgpath)
149 {
150     int  len;
151 
152     /*
153      * If the path from the config is relative, we need to make
154      * the cgroup path include the main unit processes cgroup. I.e
155      *
156      *   NXT_CGROUP_ROOT/<main process cgroup>/<cgroup path>
157      */
158     if (dir[0] != '/') {
159         len = nxt_mk_cgpath_relative(task, dir, cgpath);
160     } else {
161         len = snprintf(cgpath, NXT_MAX_PATH_LEN, NXT_CGROUP_ROOT "%s", dir);
162     }
163 
164     if (len == -1) {
165         return NXT_ERROR;
166     }
167 
168     if (len >= NXT_MAX_PATH_LEN) {
169         nxt_errno = ENAMETOOLONG;
170         return NXT_ERROR;
171     }
172 
173     return NXT_OK;
174 }
175