summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-02-24 23:50:37 +0100
committerLennart Poettering <lennart@poettering.net>2015-02-25 22:06:54 +0100
commitd6ce17c7f02ed3facdb45f65f546e587c2f00950 (patch)
tree844e595be12176a1e29163fa64f0af0b86d953bd /src
parent950c07d421c04e5aae99973479f4f13131fb45e1 (diff)
machined,machinectl: add calls for changing container/VM quotas
Diffstat (limited to 'src')
-rw-r--r--src/machine/image-dbus.c39
-rw-r--r--src/machine/image-dbus.h1
-rw-r--r--src/machine/machinectl.c54
-rw-r--r--src/machine/machined-dbus.c57
-rw-r--r--src/machine/org.freedesktop.machine1.conf12
-rw-r--r--src/shared/btrfs-util.c26
-rw-r--r--src/shared/btrfs-util.h3
-rw-r--r--src/shared/machine-image.c13
-rw-r--r--src/shared/machine-image.h2
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);