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