Add support for blkio cgroups on Linux

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
diff --git a/cgroup.c b/cgroup.c
new file mode 100644
index 0000000..15641e6
--- /dev/null
+++ b/cgroup.c
@@ -0,0 +1,115 @@
+/*
+ * Code related to setting up a blkio cgroup
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include "fio.h"
+#include "cgroup.h"
+
+static char *get_cgroup_root(struct thread_data *td)
+{
+	char *str = malloc(64);
+
+	if (td->o.cgroup)
+		sprintf(str, "%s/%s", td->o.cgroup_root, td->o.cgroup);
+	else
+		sprintf(str, "%s/%s", td->o.cgroup_root, td->o.name);
+
+	return str;
+}
+
+/*
+ * Add pid to given class
+ */
+static int cgroup_add_pid(struct thread_data *td)
+{
+	char *root, tmp[256];
+	FILE *f;
+
+	root = get_cgroup_root(td);
+	sprintf(tmp, "%s/tasks", root);
+
+	f = fopen(tmp, "w");
+	if (!f) {
+		td_verror(td, errno, "cgroup open tasks");
+		return 1;
+	}
+
+	fprintf(f, "%d", td->pid);
+	fclose(f);
+	free(root);
+	return 0;
+}
+
+/*
+ * Move pid to root class
+ */
+static int cgroup_del_pid(struct thread_data *td)
+{
+	char tmp[256];
+	FILE *f;
+
+	sprintf(tmp, "%s/tasks", td->o.cgroup_root);
+	f = fopen(tmp, "w");
+	if (!f) {
+		td_verror(td, errno, "cgroup open tasks");
+		return 1;
+	}
+
+	fprintf(f, "%d", td->pid);
+	fclose(f);
+	return 0;
+}
+
+
+int cgroup_setup(struct thread_data *td)
+{
+	char *root, tmp[256];
+	FILE *f;
+
+	/*
+	 * Create container, if it doesn't exist
+	 */
+	root = get_cgroup_root(td);
+	if (mkdir(root, 0755) < 0) {
+		int __e = errno;
+
+		if (__e != EEXIST) {
+			td_verror(td, __e, "cgroup mkdir");
+			return 1;
+		}
+	} else
+		td->o.cgroup_was_created = 1;
+
+	sprintf(tmp, "%s/blkio.weight", root);
+	f = fopen(tmp, "w");
+	if (!f) {
+		td_verror(td, errno, "cgroup open weight");
+		return 1;
+	}
+
+	fprintf(f, "%d", td->o.cgroup_weight);
+	fclose(f);
+	free(root);
+
+	if (cgroup_add_pid(td))
+		return 1;
+
+	return 0;
+}
+
+void cgroup_shutdown(struct thread_data *td)
+{
+	if (!td->o.cgroup_weight)
+		return;
+
+	cgroup_del_pid(td);
+
+	if (td->o.cgroup_was_created) {
+		char *root;
+
+		root = get_cgroup_root(td);
+		rmdir(root);
+		free(root);
+	}
+}