cgroup cleanups/fixes
[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 static int cgroup_write_pid(struct thread_data *td, const char *root)
86 {
87         char tmp[256];
88         FILE *f;
89         
90         sprintf(tmp, "%s/tasks", root);
91         f = fopen(tmp, "w");
92         if (!f) {
93                 td_verror(td, errno, "cgroup open tasks");
94                 return 1;
95         }
96
97         fprintf(f, "%d", td->pid);
98         fclose(f);
99         return 0;
100
101 }
102
103 /*
104  * Add pid to given class
105  */
106 static int cgroup_add_pid(struct thread_data *td)
107 {
108         char *root;
109         int ret;
110
111         root = get_cgroup_root(td);
112         ret = cgroup_write_pid(td, root);
113         free(root);
114         return ret;
115 }
116
117 /*
118  * Move pid to root class
119  */
120 static int cgroup_del_pid(struct thread_data *td)
121 {
122         return cgroup_write_pid(td, td->o.cgroup_root);
123 }
124
125 int cgroup_setup(struct thread_data *td)
126 {
127         char *root, tmp[256];
128         FILE *f;
129
130         if (cgroup_check_fs(td)) {
131                 log_err("fio: blkio cgroup mount point %s not valid\n",
132                                                         td->o.cgroup_root);
133                 return 1;
134         }
135
136         /*
137          * Create container, if it doesn't exist
138          */
139         root = get_cgroup_root(td);
140         if (mkdir(root, 0755) < 0) {
141                 int __e = errno;
142
143                 if (__e != EEXIST) {
144                         td_verror(td, __e, "cgroup mkdir");
145                         goto err;
146                 }
147         } else
148                 add_cgroup(root);
149
150         if (td->o.cgroup_weight) {
151                 sprintf(tmp, "%s/blkio.weight", root);
152                 f = fopen(tmp, "w");
153                 if (!f) {
154                         td_verror(td, errno, "cgroup open weight");
155                         goto err;
156                 }
157
158                 fprintf(f, "%d", td->o.cgroup_weight);
159                 fclose(f);
160         }
161
162         free(root);
163
164         if (cgroup_add_pid(td))
165                 return 1;
166
167         return 0;
168 err:
169         free(root);
170         return 1;
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 }