diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-02-24 23:50:37 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-02-25 22:06:54 +0100 |
commit | d6ce17c7f02ed3facdb45f65f546e587c2f00950 (patch) | |
tree | 844e595be12176a1e29163fa64f0af0b86d953bd /src | |
parent | 950c07d421c04e5aae99973479f4f13131fb45e1 (diff) |
machined,machinectl: add calls for changing container/VM quotas
Diffstat (limited to 'src')
-rw-r--r-- | src/machine/image-dbus.c | 39 | ||||
-rw-r--r-- | src/machine/image-dbus.h | 1 | ||||
-rw-r--r-- | src/machine/machinectl.c | 54 | ||||
-rw-r--r-- | src/machine/machined-dbus.c | 57 | ||||
-rw-r--r-- | src/machine/org.freedesktop.machine1.conf | 12 | ||||
-rw-r--r-- | src/shared/btrfs-util.c | 26 | ||||
-rw-r--r-- | src/shared/btrfs-util.h | 3 | ||||
-rw-r--r-- | src/shared/machine-image.c | 13 | ||||
-rw-r--r-- | src/shared/machine-image.h | 2 |
9 files changed, 206 insertions, 1 deletions
diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 9061017eef..12c879aff0 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -182,6 +182,44 @@ int bus_image_method_mark_read_only( return sd_bus_reply_method_return(message, NULL); } +int bus_image_method_set_limit( + sd_bus *bus, + sd_bus_message *message, + void *userdata, + sd_bus_error *error) { + + Image *image = userdata; + Manager *m = image->userdata; + uint64_t limit; + int r; + + assert(bus); + assert(message); + + r = sd_bus_message_read(message, "t", &limit); + if (r < 0) + return r; + + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.machine1.manage-images", + false, + UID_INVALID, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + + r = image_set_limit(image, limit); + if (r < 0) + return r; + + return sd_bus_reply_method_return(message, NULL); +} + const sd_bus_vtable image_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0), @@ -198,6 +236,7 @@ const sd_bus_vtable image_vtable[] = { SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; diff --git a/src/machine/image-dbus.h b/src/machine/image-dbus.h index 1b4364cbea..b9def6bc1b 100644 --- a/src/machine/image-dbus.h +++ b/src/machine/image-dbus.h @@ -34,3 +34,4 @@ int bus_image_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata int bus_image_method_rename(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_image_method_clone(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_image_method_mark_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_image_method_set_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index ddd2a4aadb..d25b5266b8 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1961,6 +1961,56 @@ static int cancel_transfer(int argc, char *argv[], void *userdata) { return 0; } +static int set_limit(int argc, char *argv[], void *userdata) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus *bus = userdata; + uint64_t limit; + int r; + + if (streq(argv[argc-1], "-")) + limit = (uint64_t) -1; + else { + off_t off; + + r = parse_size(argv[argc-1], 1024, &off); + if (r < 0) + return log_error("Failed to parse size: %s", argv[argc-1]); + + limit = (uint64_t) off; + } + + if (argc > 2) + /* With two arguments changes the quota limit of the + * specified image */ + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "SetImageLimit", + &error, + NULL, + "st", argv[1], limit); + else + /* With one argument changes the pool quota limit */ + r = sd_bus_call_method( + bus, + "org.freedesktop.machine1", + "/org/freedesktop/machine1", + "org.freedesktop.machine1.Manager", + "SetPoolLimit", + &error, + NULL, + "t", limit); + + if (r < 0) { + log_error("Could not set limit: %s", bus_error_message(&error, -r)); + return r; + } + + return 0; +} + static int help(int argc, char *argv[], void *userdata) { printf("%s [OPTIONS...] {COMMAND} ...\n\n" @@ -2012,7 +2062,8 @@ static int help(int argc, char *argv[], void *userdata) { " clone NAME NAME Clone an image\n" " rename NAME NAME Rename an image\n" " read-only NAME [BOOL] Mark or unmark image read-only\n" - " remove NAME... Remove an image\n\n" + " remove NAME... Remove an image\n" + " set-limit [NAME] BYTES Set image size limit (quota)\n\n" "Image Transfer Commands:\n" " pull-tar URL [NAME] Download a TAR container image\n" " pull-raw URL [NAME] Download a RAW container or VM image\n" @@ -2221,6 +2272,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { { "pull-dkr", 2, 3, 0, pull_dkr }, { "list-transfers", VERB_ANY, 1, 0, list_transfers }, { "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer }, + { "set-limit", 2, 3, 0, set_limit }, {} }; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index c4f60b5b02..fdb9d5fac8 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -776,6 +776,61 @@ static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, voi return bus_image_method_mark_read_only(bus, message, i, error); } +static int method_set_pool_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + uint64_t limit; + int r; + + assert(bus); + r = sd_bus_message_read(message, "t", &limit); + if (r < 0) + return r; + + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.machine1.manage-machines", + false, + UID_INVALID, + &m->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ + + r = btrfs_quota_limit("/var/lib/machines", limit); + if (r == -ENOTTY) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs."); + else if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m"); + + return sd_bus_reply_method_return(message, NULL); +} + +static int method_set_image_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_(image_unrefp) Image *i = NULL; + const char *name; + int r; + + assert(bus); + r = sd_bus_message_read(message, "s", &name); + if (r < 0) + return r; + + if (!image_name_is_valid(name)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name); + + r = image_find(name, &i); + if (r < 0) + return r; + if (r == 0) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name); + + i->userdata = userdata; + return bus_image_method_set_limit(bus, message, i, error); +} + const sd_bus_vtable manager_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0), @@ -803,6 +858,8 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_SIGNAL("MachineNew", "so", 0), SD_BUS_SIGNAL("MachineRemoved", "so", 0), SD_BUS_VTABLE_END diff --git a/src/machine/org.freedesktop.machine1.conf b/src/machine/org.freedesktop.machine1.conf index 0e99933488..93aaf6a377 100644 --- a/src/machine/org.freedesktop.machine1.conf +++ b/src/machine/org.freedesktop.machine1.conf @@ -105,6 +105,14 @@ send_member="MarkImageReadOnly"/> <allow send_destination="org.freedesktop.machine1" + send_interface="org.freedesktop.machine1.Manager" + send_member="SetPoolLimit"/> + + <allow send_destination="org.freedesktop.machine1" + send_interface="org.freedesktop.machine1.Manager" + send_member="SetImageLimit"/> + + <allow send_destination="org.freedesktop.machine1" send_interface="org.freedesktop.machine1.Machine" send_member="GetAddresses"/> @@ -150,6 +158,10 @@ <allow send_destination="org.freedesktop.machine1" send_interface="org.freedesktop.machine1.Image" + send_member="SetLimit"/> + + <allow send_destination="org.freedesktop.machine1" + send_interface="org.freedesktop.machine1.Image" send_member="MarkReadOnly"/> <allow receive_sender="org.freedesktop.machine1"/> diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index 980963b748..6761501da2 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -669,3 +669,29 @@ int btrfs_quota_enable(const char *path, bool b) { return btrfs_quota_enable_fd(fd, b); } + +int btrfs_quota_limit_fd(int fd, uint64_t referred_max) { + struct btrfs_ioctl_qgroup_limit_args args = { + .lim.max_rfer = + referred_max == (uint64_t) -1 ? 0 : + referred_max == 0 ? 1 : referred_max, + .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER, + }; + + assert(fd >= 0); + + if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0) + return -errno; + + return 0; +} + +int btrfs_quota_limit(const char *path, uint64_t referred_max) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return btrfs_quota_limit_fd(fd, referred_max); +} diff --git a/src/shared/btrfs-util.h b/src/shared/btrfs-util.h index 93c3f13ed5..9a1eb3f383 100644 --- a/src/shared/btrfs-util.h +++ b/src/shared/btrfs-util.h @@ -67,3 +67,6 @@ int btrfs_defrag(const char *p); int btrfs_quota_enable_fd(int fd, bool b); int btrfs_quota_enable(const char *path, bool b); + +int btrfs_quota_limit_fd(int fd, uint64_t referred_max); +int btrfs_quota_limit(const char *path, uint64_t referred_max); diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index c734f148ae..c6d2850ad2 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -613,6 +613,19 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile return 0; } +int image_set_limit(Image *i, uint64_t referred_max) { + assert(i); + + if (path_equal(i->path, "/") || + path_startswith(i->path, "/usr")) + return -EROFS; + + if (i->type != IMAGE_SUBVOLUME) + return -ENOTSUP; + + return btrfs_quota_limit(i->path, referred_max); +} + int image_name_lock(const char *name, int operation, LockFile *ret) { const char *p; diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h index 314fd6da58..df2394991f 100644 --- a/src/shared/machine-image.h +++ b/src/shared/machine-image.h @@ -70,3 +70,5 @@ bool image_name_is_valid(const char *s) _pure_; int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local); int image_name_lock(const char *name, int operation, LockFile *ret); + +int image_set_limit(Image *i, uint64_t referred_max); |