X-Git-Url: https://git.kernel.dk/?p=fio.git;a=blobdiff_plain;f=cgroup.c;h=77e31a4d0e222fd4f03ccbccb92a48a7c1457d9a;hp=548740a08e9bd0f12741def199e40dc8843cc50d;hb=d643a1e29d31bf974a613866819dde241c928b6d;hpb=ddf16fe4da558a2778bf1ba06c965080d318cb24 diff --git a/cgroup.c b/cgroup.c index 548740a0..77e31a4d 100644 --- a/cgroup.c +++ b/cgroup.c @@ -3,133 +3,235 @@ */ #include #include +#include +#include #include "fio.h" +#include "flist.h" #include "cgroup.h" +#include "smalloc.h" -/* - * Check if the given root appears valid - */ -static int cgroup_check_fs(struct thread_data *td) +static struct fio_sem *lock; + +struct cgroup_member { + struct flist_head list; + char *root; + unsigned int cgroup_nodelete; +}; + +static struct cgroup_mnt *find_cgroup_mnt(struct thread_data *td) { - struct stat sb; - char tmp[256]; + 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); - sprintf(tmp, "%s/tasks", td->o.cgroup_root); - return stat(tmp, &sb); + 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_sem_up(lock); } -static char *get_cgroup_root(struct thread_data *td) +static char *get_cgroup_root(struct thread_data *td, struct cgroup_mnt *mnt) { char *str = malloc(64); if (td->o.cgroup) - sprintf(str, "%s/%s", td->o.cgroup_root, td->o.cgroup); + sprintf(str, "%s/%s", mnt->path, td->o.cgroup); else - sprintf(str, "%s/%s", td->o.cgroup_root, td->o.name); + sprintf(str, "%s/%s", mnt->path, td->o.name); return str; } -/* - * Add pid to given class - */ -static int cgroup_add_pid(struct thread_data *td) +static int write_int_to_file(struct thread_data *td, const char *path, + const char *filename, unsigned int val, + const char *onerr) { - char *root, tmp[256]; + char tmp[256]; FILE *f; - root = get_cgroup_root(td); - sprintf(tmp, "%s/tasks", root); - + sprintf(tmp, "%s/%s", path, filename); f = fopen(tmp, "w"); if (!f) { - td_verror(td, errno, "cgroup open tasks"); + td_verror(td, errno, onerr); return 1; } - fprintf(f, "%d", td->pid); + fprintf(f, "%u", val); fclose(f); - free(root); return 0; + +} + +static int cgroup_write_pid(struct thread_data *td, char *path, bool cgroup2) +{ + unsigned int val = td->pid; + + if (cgroup2) + return write_int_to_file(td, path, "cgroup.procs", + val, "cgroup write pid"); + return write_int_to_file(td, path, "tasks", val, "cgroup write pid"); } /* * Move pid to root class */ -static int cgroup_del_pid(struct thread_data *td) +static int cgroup_del_pid(struct thread_data *td, struct cgroup_mnt *mnt) { - 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; + return cgroup_write_pid(td, mnt->path, mnt->cgroup2); } - -int cgroup_setup(struct thread_data *td) +int cgroup_setup(struct thread_data *td, struct flist_head *clist, struct cgroup_mnt **mnt) { - char *root, tmp[256]; - FILE *f; + char *root; - if (cgroup_check_fs(td)) { - log_err("fio: blkio cgroup mount point %s not valid\n", - td->o.cgroup_root); + if (!clist) return 1; + + if (!*mnt) { + *mnt = find_cgroup_mnt(td); + if (!*mnt) + return 1; } /* * Create container, if it doesn't exist */ - root = get_cgroup_root(td); + root = get_cgroup_root(td, *mnt); if (mkdir(root, 0755) < 0) { int __e = errno; if (__e != EEXIST) { td_verror(td, __e, "cgroup mkdir"); - return 1; + log_err("fio: path %s\n", root); + goto err; } } else - td->o.cgroup_was_created = 1; + add_cgroup(td, root, clist); - sprintf(tmp, "%s/blkio.weight", root); - f = fopen(tmp, "w"); - if (!f) { - td_verror(td, errno, "cgroup open weight"); - return 1; + if (td->o.cgroup_weight) { + if ((*mnt)->cgroup2) { + log_err("fio: cgroup weit doesn't work with cgroup2\n"); + goto err; + } + if (write_int_to_file(td, root, "blkio.weight", + td->o.cgroup_weight, + "cgroup open weight")) + goto err; } - fprintf(f, "%d", td->o.cgroup_weight); - fclose(f); - free(root); - - if (cgroup_add_pid(td)) - return 1; + if (!cgroup_write_pid(td, root, (*mnt)->cgroup2)) { + free(root); + return 0; + } - return 0; +err: + free(root); + return 1; } -void cgroup_shutdown(struct thread_data *td) +void cgroup_shutdown(struct thread_data *td, struct cgroup_mnt *mnt) { - if (cgroup_check_fs(td)) - return; - if (!td->o.cgroup_weight) + if (mnt == NULL) return; + if (!td->o.cgroup_weight && !td->o.cgroup) + goto out; + + cgroup_del_pid(td, mnt); +out: + if (mnt->path) + sfree(mnt->path); + sfree(mnt); +} - cgroup_del_pid(td); - - if (td->o.cgroup_was_created) { - char *root; +static void fio_init cgroup_init(void) +{ + lock = fio_sem_init(FIO_SEM_UNLOCKED); + if (!lock) + log_err("fio: failed to allocate cgroup lock\n"); +} - root = get_cgroup_root(td); - rmdir(root); - free(root); - } +static void fio_exit cgroup_exit(void) +{ + fio_sem_remove(lock); }