+ struct cgroup_mnt *cgroup_mnt = NULL;
+ struct mntent *mnt, dummy;
+ char buf[256] = {0};
+ FILE *f;
+ bool cgroup2 = false;
+
+ 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 (!strcmp(mnt->mnt_type, "cgroup2")) {
+ cgroup2 = true;
+ break;
+ }
+ }
+
+ if (mnt) {
+ cgroup_mnt = smalloc(sizeof(*cgroup_mnt));
+ if (cgroup_mnt) {
+ cgroup_mnt->path = smalloc_strdup(mnt->mnt_dir);
+ if (!cgroup_mnt->path) {
+ sfree(cgroup_mnt);
+ log_err("fio: could not allocate memory\n");
+ } else {
+ cgroup_mnt->cgroup2 = cgroup2;
+ }
+ }
+ } else {
+ log_err("fio: cgroup blkio does not appear to be mounted\n");
+ }
+
+ endmntent(f);
+ return cgroup_mnt;
+}
+
+static void add_cgroup(struct thread_data *td, const char *name,
+ struct flist_head *clist)
+{
+ struct cgroup_member *cm;
+
+ if (!lock)
+ return;
+
+ cm = smalloc(sizeof(*cm));
+ if (!cm) {
+err:
+ log_err("fio: failed to allocate cgroup member\n");
+ return;
+ }
+
+ INIT_FLIST_HEAD(&cm->list);
+ cm->root = smalloc_strdup(name);
+ if (!cm->root) {
+ sfree(cm);
+ goto err;
+ }
+ if (td->o.cgroup_nodelete)
+ cm->cgroup_nodelete = 1;
+ fio_sem_down(lock);
+ flist_add_tail(&cm->list, clist);
+ fio_sem_up(lock);
+}
+
+void cgroup_kill(struct flist_head *clist)
+{
+ struct flist_head *n, *tmp;
+ struct cgroup_member *cm;
+
+ if (!lock)
+ return;
+
+ fio_sem_down(lock);