+static struct fio_mutex *lock;
+
+struct cgroup_member {
+ struct flist_head list;
+ char *root;
+ unsigned int cgroup_nodelete;
+};
+
+static char *find_cgroup_mnt(struct thread_data *td)
+{
+ char *mntpoint = NULL;
+ struct mntent *mnt, dummy;
+ char buf[256] = {0};
+ FILE *f;
+
+ f = setmntent("/proc/mounts", "r");
+ if (!f) {
+ td_verror(td, errno, "setmntent /proc/mounts");
+ return NULL;
+ }
+
+ while ((mnt = getmntent_r(f, &dummy, buf, sizeof(buf))) != NULL) {
+ if (!strcmp(mnt->mnt_type, "cgroup") &&
+ strstr(mnt->mnt_opts, "blkio"))
+ break;
+ }
+
+ if (mnt)
+ mntpoint = smalloc_strdup(mnt->mnt_dir);
+ else
+ log_err("fio: cgroup blkio does not appear to be mounted\n");
+
+ endmntent(f);
+ return mntpoint;
+}
+
+static void add_cgroup(struct thread_data *td, const char *name,
+ struct flist_head *clist)
+{
+ struct cgroup_member *cm;
+
+ cm = smalloc(sizeof(*cm));
+ INIT_FLIST_HEAD(&cm->list);
+ cm->root = smalloc_strdup(name);
+ if (td->o.cgroup_nodelete)
+ cm->cgroup_nodelete = 1;
+ fio_mutex_down(lock);
+ flist_add_tail(&cm->list, clist);
+ fio_mutex_up(lock);
+}
+
+void cgroup_kill(struct flist_head *clist)
+{
+ struct flist_head *n, *tmp;
+ struct cgroup_member *cm;
+
+ fio_mutex_down(lock);
+
+ flist_for_each_safe(n, tmp, clist) {
+ cm = flist_entry(n, struct cgroup_member, list);
+ if (!cm->cgroup_nodelete)
+ rmdir(cm->root);
+ flist_del(&cm->list);
+ sfree(cm->root);
+ sfree(cm);
+ }
+
+ fio_mutex_up(lock);
+}
+
+static char *get_cgroup_root(struct thread_data *td, char *mnt)