1a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe/*
2a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe * Code related to setting up a blkio cgroup
3a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe */
4a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe#include <stdio.h>
5a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe#include <stdlib.h>
66adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe#include <mntent.h>
74f49b8a762f20279095e5c27c51a6afc629b835fJens Axboe#include <sys/stat.h>
84f49b8a762f20279095e5c27c51a6afc629b835fJens Axboe#include <sys/types.h>
9a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe#include "fio.h"
1039f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe#include "flist.h"
11a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe#include "cgroup.h"
1239f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe#include "smalloc.h"
1339f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe
1439f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboestatic struct fio_mutex *lock;
1539f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe
1639f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboestruct cgroup_member {
1739f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	struct flist_head list;
1839f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	char *root;
197de870993035f855e1d1299a2b5c2c90b792c238Vivek Goyal	unsigned int cgroup_nodelete;
2039f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe};
2139f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe
226adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboestatic char *find_cgroup_mnt(struct thread_data *td)
236adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe{
246adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	char *mntpoint = NULL;
25599e72b74ed2c44fd846b95160c5037c16438994Zhu Yanhai	struct mntent *mnt, dummy;
26599e72b74ed2c44fd846b95160c5037c16438994Zhu Yanhai	char buf[256] = {0};
276adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	FILE *f;
286adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe
296adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	f = setmntent("/proc/mounts", "r");
306adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	if (!f) {
316adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe		td_verror(td, errno, "setmntent /proc/mounts");
326adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe		return NULL;
336adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	}
346adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe
35599e72b74ed2c44fd846b95160c5037c16438994Zhu Yanhai	while ((mnt = getmntent_r(f, &dummy, buf, sizeof(buf))) != NULL) {
366adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe		if (!strcmp(mnt->mnt_type, "cgroup") &&
376adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe		    strstr(mnt->mnt_opts, "blkio"))
386adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe			break;
396adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	}
406adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe
416adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	if (mnt)
426adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe		mntpoint = smalloc_strdup(mnt->mnt_dir);
436adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	else
446adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe		log_err("fio: cgroup blkio does not appear to be mounted\n");
456adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe
466adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	endmntent(f);
476adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	return mntpoint;
486adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe}
496adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe
507de870993035f855e1d1299a2b5c2c90b792c238Vivek Goyalstatic void add_cgroup(struct thread_data *td, const char *name,
517de870993035f855e1d1299a2b5c2c90b792c238Vivek Goyal			struct flist_head *clist)
5239f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe{
5339f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	struct cgroup_member *cm;
5439f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe
55fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe	if (!lock)
56fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe		return;
57fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe
5839f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	cm = smalloc(sizeof(*cm));
59fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe	if (!cm) {
60fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboeerr:
61fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe		log_err("fio: failed to allocate cgroup member\n");
62fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe		return;
63fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe	}
64fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe
6539f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	INIT_FLIST_HEAD(&cm->list);
6639f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	cm->root = smalloc_strdup(name);
67fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe	if (!cm->root) {
68fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe		sfree(cm);
69fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe		goto err;
70fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe	}
717de870993035f855e1d1299a2b5c2c90b792c238Vivek Goyal	if (td->o.cgroup_nodelete)
727de870993035f855e1d1299a2b5c2c90b792c238Vivek Goyal		cm->cgroup_nodelete = 1;
7339f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	fio_mutex_down(lock);
74dae5341c3059273242598de2bc27cc9f18c627c1Jens Axboe	flist_add_tail(&cm->list, clist);
7539f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	fio_mutex_up(lock);
7639f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe}
7739f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe
78dae5341c3059273242598de2bc27cc9f18c627c1Jens Axboevoid cgroup_kill(struct flist_head *clist)
7939f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe{
8039f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	struct flist_head *n, *tmp;
8139f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	struct cgroup_member *cm;
8239f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe
83fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe	if (!lock)
84fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe		return;
85fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe
8639f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	fio_mutex_down(lock);
8739f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe
88dae5341c3059273242598de2bc27cc9f18c627c1Jens Axboe	flist_for_each_safe(n, tmp, clist) {
8939f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe		cm = flist_entry(n, struct cgroup_member, list);
907de870993035f855e1d1299a2b5c2c90b792c238Vivek Goyal		if (!cm->cgroup_nodelete)
917de870993035f855e1d1299a2b5c2c90b792c238Vivek Goyal			rmdir(cm->root);
9239f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe		flist_del(&cm->list);
9339f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe		sfree(cm->root);
9439f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe		sfree(cm);
9539f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	}
9639f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe
9739f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	fio_mutex_up(lock);
9839f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe}
99a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1006adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboestatic char *get_cgroup_root(struct thread_data *td, char *mnt)
101a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe{
102a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	char *str = malloc(64);
103a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
104a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	if (td->o.cgroup)
105eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes		sprintf(str, "%s/%s", mnt, td->o.cgroup);
106a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	else
107eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes		sprintf(str, "%s/%s", mnt, td->o.name);
108a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
109a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	return str;
110a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe}
111a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1128a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboestatic int write_int_to_file(struct thread_data *td, const char *path,
1138a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe			     const char *filename, unsigned int val,
1148a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe			     const char *onerr)
115a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe{
1163858bf9eb509136b800cda1a08247e9c0ff167b9Jens Axboe	char tmp[256];
117a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	FILE *f;
118b9fd788f0e8adacc33316107594e9eb0463743d7Bruce Cran
119eda3a60699e1d96bb68875ef2169ca819eb8f4f9Elliott Hughes	sprintf(tmp, "%s/%s", path, filename);
120a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	f = fopen(tmp, "w");
121a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	if (!f) {
1228a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe		td_verror(td, errno, onerr);
123a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe		return 1;
124a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	}
125a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1268a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe	fprintf(f, "%u", val);
127a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	fclose(f);
128a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	return 0;
1298a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe
130a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe}
131a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1328a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboestatic int cgroup_write_pid(struct thread_data *td, const char *root)
133a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe{
1348a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe	unsigned int val = td->pid;
135a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1368a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe	return write_int_to_file(td, root, "tasks", val, "cgroup write pid");
137a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe}
138a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1393858bf9eb509136b800cda1a08247e9c0ff167b9Jens Axboe/*
1403858bf9eb509136b800cda1a08247e9c0ff167b9Jens Axboe * Move pid to root class
1413858bf9eb509136b800cda1a08247e9c0ff167b9Jens Axboe */
1426adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboestatic int cgroup_del_pid(struct thread_data *td, char *mnt)
1433858bf9eb509136b800cda1a08247e9c0ff167b9Jens Axboe{
1446adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	return cgroup_write_pid(td, mnt);
1453858bf9eb509136b800cda1a08247e9c0ff167b9Jens Axboe}
146a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1476adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboeint cgroup_setup(struct thread_data *td, struct flist_head *clist, char **mnt)
148a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe{
1498a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe	char *root;
150a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1516adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	if (!*mnt) {
1526adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe		*mnt = find_cgroup_mnt(td);
1536adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe		if (!*mnt)
1546adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe			return 1;
155ddf16fe4da558a2778bf1ba06c965080d318cb24Jens Axboe	}
156ddf16fe4da558a2778bf1ba06c965080d318cb24Jens Axboe
157a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	/*
158a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	 * Create container, if it doesn't exist
159a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	 */
1606adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	root = get_cgroup_root(td, *mnt);
161a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	if (mkdir(root, 0755) < 0) {
162a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe		int __e = errno;
163a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
164a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe		if (__e != EEXIST) {
165a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe			td_verror(td, __e, "cgroup mkdir");
1666adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe			log_err("fio: path %s\n", root);
1673858bf9eb509136b800cda1a08247e9c0ff167b9Jens Axboe			goto err;
168a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe		}
169a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	} else
1707de870993035f855e1d1299a2b5c2c90b792c238Vivek Goyal		add_cgroup(td, root, clist);
171a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
17239f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	if (td->o.cgroup_weight) {
1738a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe		if (write_int_to_file(td, root, "blkio.weight",
1748a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe					td->o.cgroup_weight,
1758a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe					"cgroup open weight"))
1763858bf9eb509136b800cda1a08247e9c0ff167b9Jens Axboe			goto err;
177a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe	}
178a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1798a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe	if (!cgroup_write_pid(td, root)) {
1808a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe		free(root);
1818a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe		return 0;
1828a4d0ff0b2d8192ef58e69b7f2a3c976f3bebd5cJens Axboe	}
183a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1843858bf9eb509136b800cda1a08247e9c0ff167b9Jens Axboeerr:
1853858bf9eb509136b800cda1a08247e9c0ff167b9Jens Axboe	free(root);
1863858bf9eb509136b800cda1a08247e9c0ff167b9Jens Axboe	return 1;
187a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe}
188a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1896adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboevoid cgroup_shutdown(struct thread_data *td, char **mnt)
190a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe{
1916adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	if (*mnt == NULL)
192ddf16fe4da558a2778bf1ba06c965080d318cb24Jens Axboe		return;
193ed81ee199ec8f3cdfcdc78ff067a0397c3b02f5fJens Axboe	if (!td->o.cgroup_weight && !td->o.cgroup)
194a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe		return;
195a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
1966adb38a1a1cbe95f7131815416c8bb31683c3f47Jens Axboe	cgroup_del_pid(td, *mnt);
19739f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe}
198a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe
19939f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboestatic void fio_init cgroup_init(void)
20039f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe{
201521da527743088a9bd2ab882f8b64799d49d5848Jens Axboe	lock = fio_mutex_init(FIO_MUTEX_UNLOCKED);
202fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe	if (!lock)
203fba5c5ff89163062922c3e560e871c087f2177c3Jens Axboe		log_err("fio: failed to allocate cgroup lock\n");
20439f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe}
20539f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe
20639f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboestatic void fio_exit cgroup_exit(void)
20739f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe{
20839f22027248f658ade599e89c2fe6afae02ac9d7Jens Axboe	fio_mutex_remove(lock);
209a696fa2a9c2e21a1c88813235d6fc39d267f6155Jens Axboe}
210