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