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