Better support for setting up and removing private cgroups
[fio.git] / cgroup.c
1 /*
2  * Code related to setting up a blkio cgroup
3  */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include "fio.h"
7 #include "flist.h"
8 #include "cgroup.h"
9 #include "smalloc.h"
10
11 static struct flist_head *cgroup_list;
12 static struct fio_mutex *lock;
13
14 struct cgroup_member {
15         struct flist_head list;
16         char *root;
17 };
18
19 static void add_cgroup(const char *name)
20 {
21         struct cgroup_member *cm;
22
23         cm = smalloc(sizeof(*cm));
24         INIT_FLIST_HEAD(&cm->list);
25         cm->root = smalloc_strdup(name);
26
27         fio_mutex_down(lock);
28
29         if (!cgroup_list) {
30                 cgroup_list = smalloc(sizeof(struct flist_head));
31                 INIT_FLIST_HEAD(cgroup_list);
32         }
33
34         flist_add_tail(&cm->list, cgroup_list);
35         fio_mutex_up(lock);
36 }
37
38 void cgroup_kill(void)
39 {
40         struct flist_head *n, *tmp;
41         struct cgroup_member *cm;
42
43         fio_mutex_down(lock);
44         if (!cgroup_list)
45                 goto out;
46
47         flist_for_each_safe(n, tmp, cgroup_list) {
48                 cm = flist_entry(n, struct cgroup_member, list);
49                 rmdir(cm->root);
50                 flist_del(&cm->list);
51                 sfree(cm->root);
52                 sfree(cm);
53         }
54
55         sfree(cgroup_list);
56         cgroup_list = NULL;
57 out:
58         fio_mutex_up(lock);
59 }
60
61 /*
62  * Check if the given root appears valid
63  */
64 static int cgroup_check_fs(struct thread_data *td)
65 {
66         struct stat sb;
67         char tmp[256];
68
69         sprintf(tmp, "%s/tasks", td->o.cgroup_root);
70         return stat(tmp, &sb);
71 }
72
73 static char *get_cgroup_root(struct thread_data *td)
74 {
75         char *str = malloc(64);
76
77         if (td->o.cgroup)
78                 sprintf(str, "%s/%s", td->o.cgroup_root, td->o.cgroup);
79         else
80                 sprintf(str, "%s/%s", td->o.cgroup_root, td->o.name);
81
82         return str;
83 }
84
85 /*
86  * Add pid to given class
87  */
88 static int cgroup_add_pid(struct thread_data *td)
89 {
90         char *root, tmp[256];
91         FILE *f;
92
93         root = get_cgroup_root(td);
94         sprintf(tmp, "%s/tasks", root);
95         f = fopen(tmp, "w");
96         if (!f) {
97                 td_verror(td, errno, "cgroup open tasks");
98                 return 1;
99         }
100
101         fprintf(f, "%d", td->pid);
102         fclose(f);
103         free(root);
104         return 0;
105 }
106
107 /*
108  * Move pid to root class
109  */
110 static int cgroup_del_pid(struct thread_data *td)
111 {
112         char tmp[256];
113         FILE *f;
114
115         sprintf(tmp, "%s/tasks", td->o.cgroup_root);
116         f = fopen(tmp, "w");
117         if (!f) {
118                 td_verror(td, errno, "cgroup open tasks");
119                 return 1;
120         }
121
122         fprintf(f, "%d", td->pid);
123         fclose(f);
124         return 0;
125 }
126
127
128 int cgroup_setup(struct thread_data *td)
129 {
130         char *root, tmp[256];
131         FILE *f;
132
133         if (cgroup_check_fs(td)) {
134                 log_err("fio: blkio cgroup mount point %s not valid\n",
135                                                         td->o.cgroup_root);
136                 return 1;
137         }
138
139         /*
140          * Create container, if it doesn't exist
141          */
142         root = get_cgroup_root(td);
143         if (mkdir(root, 0755) < 0) {
144                 int __e = errno;
145
146                 if (__e != EEXIST) {
147                         td_verror(td, __e, "cgroup mkdir");
148                         return 1;
149                 }
150         } else
151                 add_cgroup(root);
152
153         if (td->o.cgroup_weight) {
154                 sprintf(tmp, "%s/blkio.weight", root);
155                 f = fopen(tmp, "w");
156                 if (!f) {
157                         td_verror(td, errno, "cgroup open weight");
158                         return 1;
159                 }
160
161                 fprintf(f, "%d", td->o.cgroup_weight);
162                 fclose(f);
163         }
164
165         free(root);
166
167         if (cgroup_add_pid(td))
168                 return 1;
169
170         return 0;
171 }
172
173 void cgroup_shutdown(struct thread_data *td)
174 {
175         if (cgroup_check_fs(td))
176                 return;
177         if (!td->o.cgroup_weight && td->o.cgroup)
178                 return;
179
180         cgroup_del_pid(td);
181 }
182
183
184 static void fio_init cgroup_init(void)
185 {
186         lock = fio_mutex_init(1);
187 }
188
189 static void fio_exit cgroup_exit(void)
190 {
191         fio_mutex_remove(lock);
192 }