From: Lennart Poettering Date: Sat, 20 Aug 2011 22:28:30 +0000 (+0200) Subject: exec: allow passing arbitrary path names to blkio cgroup attributes X-Git-Tag: v34~24 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=94959f0fa0c19ae1db0e63d9a5dfc94c660825ba;p=systemd exec: allow passing arbitrary path names to blkio cgroup attributes If a device node is specified, then adjust the bandwidth/weight of it, otherwise find the backing block device of the file system the path refers to and adjust its bandwidth/weight. --- diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 6bc8bf3e..ce6833b8 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -859,10 +859,15 @@ processes. Takes either a single weight value (between 10 and 1000) to set the default block IO weight, or a - space separated pair of a device node - path and a weight value to specify the + space separated pair of a file path + and a weight value to specify the device specific weight value (Example: - "/dev/sda 500"). This controls the + "/dev/sda 500"). The file path may be + specified as path to a block device + node or as any other file in which + case the backing block device of the + file system of the file is + determined. This controls the blkio.weight and blkio.weight_device control group attributes, which @@ -879,17 +884,22 @@ BlockIOWriteBandwidth= Set the per-device - overall block IO bandwith limit for the - executed processes. Takes a space - separated pair of a device node path - and a bandwith value (in bytes per - second) to specify the device specific - bandwidth. If the bandwith is suffixed - with K, M, G, or T the specified - bandwith is parsed as Kilobytes, - Megabytes, Gigabytes, resp. Terabytes - (Example: "/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 5M"). This - controls the + overall block IO bandwith limit for + the executed processes. Takes a space + separated pair of a file path and a + bandwith value (in bytes per second) + to specify the device specific + bandwidth. The file path may be + specified as path to a block device + node or as any other file in which + case the backing block device of the + file system of the file is determined. + If the bandwith is suffixed with K, M, + G, or T the specified bandwith is + parsed as Kilobytes, Megabytes, + Gigabytes, resp. Terabytes (Example: + "/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 + 5M"). This controls the blkio.read_bps_device and blkio.write_bps_device diff --git a/src/load-fragment.c b/src/load-fragment.c index b122ea41..c8b4b5a9 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -1843,6 +1843,7 @@ int config_parse_unit_device_allow(const char *filename, unsigned line, const ch static int blkio_map(const char *controller, const char *name, const char *value, char **ret) { struct stat st; char **l; + dev_t d; assert(controller); assert(name); @@ -1861,13 +1862,23 @@ static int blkio_map(const char *controller, const char *name, const char *value return -errno; } - if (!S_ISBLK(st.st_mode)) { - log_warning("%s is not a block device.", l[0]); + if (S_ISBLK(st.st_mode)) + d = st.st_rdev; + else if (major(st.st_dev) != 0) { + /* If this is not a device node then find the block + * device this file is stored on */ + d = st.st_dev; + + /* If this is a partition, try to get the originating + * block device */ + block_get_whole_disk(d, &d); + } else { + log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]); strv_free(l); return -ENODEV; } - if (asprintf(ret, "%u:%u %s", major(st.st_rdev), minor(st.st_rdev), l[1]) < 0) { + if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) { strv_free(l); return -ENOMEM; } @@ -1907,7 +1918,7 @@ int config_parse_unit_blkio_weight(const char *filename, unsigned line, const ch weight = l[1]; } - if (device && !path_startswith(device, "/dev/")) { + if (device && !path_is_absolute(device)) { log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue); strv_free(l); return 0; @@ -1965,7 +1976,7 @@ int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const return 0; } - if (!path_startswith(l[0], "/dev/")) { + if (!path_is_absolute(l[0])) { log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue); strv_free(l); return 0; diff --git a/src/util.c b/src/util.c index c24c749a..017b9958 100644 --- a/src/util.c +++ b/src/util.c @@ -5614,6 +5614,67 @@ bool is_main_thread(void) { return cached > 0; } +int block_get_whole_disk(dev_t d, dev_t *ret) { + char *p, *s; + int r; + unsigned n, m; + + assert(ret); + + /* If it has a queue this is good enough for us */ + if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r >= 0) { + *ret = d; + return 0; + } + + /* If it is a partition find the originating device */ + if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r < 0) + return -ENOENT; + + /* Get parent dev_t */ + if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0) + return -ENOMEM; + + r = read_one_line_file(p, &s); + free(p); + + if (r < 0) + return r; + + r = sscanf(s, "%u:%u", &m, &n); + free(s); + + if (r != 2) + return -EINVAL; + + /* Only return this if it is really good enough for us. */ + if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r >= 0) { + *ret = makedev(m, n); + return 0; + } + + return -ENOENT; +} + + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/util.h b/src/util.h index 54873e64..e23f309d 100644 --- a/src/util.h +++ b/src/util.h @@ -465,6 +465,8 @@ bool is_main_thread(void); bool in_charset(const char *s, const char* charset); +int block_get_whole_disk(dev_t d, dev_t *ret); + #define NULSTR_FOREACH(i, l) \ for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)