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