Home | History | Annotate | Download | only in fio
      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", mnt, td->o.cgroup);
    106 	else
    107 		sprintf(str, "%s/%s", mnt, 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", path, 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