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