Skip to content

Commit d6ce17c

Browse files
committed
machined,machinectl: add calls for changing container/VM quotas
1 parent 950c07d commit d6ce17c

File tree

10 files changed

+226
-6
lines changed

10 files changed

+226
-6
lines changed

man/machinectl.xml

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@
469469
<varlistentry>
470470
<term><command>clone</command> <replaceable>NAME</replaceable> <replaceable>NAME</replaceable></term>
471471

472-
<listitem><para>Clones a container or disk image. The
472+
<listitem><para>Clones a container or VM image. The
473473
arguments specify the name of the image to clone and the name
474474
of the newly cloned image. Note that plain directory container
475475
images are cloned into subvolume images with this command.
@@ -481,30 +481,45 @@
481481
<varlistentry>
482482
<term><command>rename</command> <replaceable>NAME</replaceable> <replaceable>NAME</replaceable></term>
483483

484-
<listitem><para>Renames a container or disk image. The
484+
<listitem><para>Renames a container or VM image. The
485485
arguments specify the name of the image to rename and the new
486486
name of the image.</para></listitem>
487487
</varlistentry>
488488

489489
<varlistentry>
490490
<term><command>read-only</command> <replaceable>NAME</replaceable> [<replaceable>BOOL</replaceable>]</term>
491491

492-
<listitem><para>Marks or (unmarks) a container or disk image
492+
<listitem><para>Marks or (unmarks) a container or VM image
493493
read-only. Takes a VM or container image name, followed by a
494494
boolean as arguments. If the boolean is omitted, positive is
495495
implied, i.e. the image is marked read-only.</para></listitem>
496496
</varlistentry>
497497

498-
499498
<varlistentry>
500499
<term><command>remove</command> <replaceable>NAME</replaceable>...</term>
501500

502-
<listitem><para>Removes one or more container or disk images.
501+
<listitem><para>Removes one or more container or VM images.
503502
The special image <literal>.host</literal>, which refers to
504503
the host's own directory tree may not be
505504
removed.</para></listitem>
506505
</varlistentry>
507506

507+
<varlistentry>
508+
<term><command>set-limit</command> [<replaceable>NAME</replaceable>] <replaceable>BYTES</replaceable></term>
509+
510+
<listitem><para>Sets the maximum size in bytes a specific
511+
container or VM image, or all images may grow up to
512+
(quota). Takes either one or two parameters. The first,
513+
optional parameter refers to a container or VM image name. If
514+
specified the size limit of the specified images is
515+
changed. If omitted the overall size limit of the sum of all
516+
images stored locally is changed. The final argument specifies
517+
the size limit in bytes, possibly suffixed by the usual K, M,
518+
G, T units. If the size limit shall be disabled, specify
519+
<literal>-</literal> as size. This operation is currently only
520+
supported on btrfs subvolume images.</para></listitem>
521+
</varlistentry>
522+
508523
</variablelist></refsect2>
509524

510525
<refsect2><title>Image Transfer Commands</title><variablelist>

src/machine/image-dbus.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,44 @@ int bus_image_method_mark_read_only(
182182
return sd_bus_reply_method_return(message, NULL);
183183
}
184184

185+
int bus_image_method_set_limit(
186+
sd_bus *bus,
187+
sd_bus_message *message,
188+
void *userdata,
189+
sd_bus_error *error) {
190+
191+
Image *image = userdata;
192+
Manager *m = image->userdata;
193+
uint64_t limit;
194+
int r;
195+
196+
assert(bus);
197+
assert(message);
198+
199+
r = sd_bus_message_read(message, "t", &limit);
200+
if (r < 0)
201+
return r;
202+
203+
r = bus_verify_polkit_async(
204+
message,
205+
CAP_SYS_ADMIN,
206+
"org.freedesktop.machine1.manage-images",
207+
false,
208+
UID_INVALID,
209+
&m->polkit_registry,
210+
error);
211+
if (r < 0)
212+
return r;
213+
if (r == 0)
214+
return 1; /* Will call us back */
215+
216+
r = image_set_limit(image, limit);
217+
if (r < 0)
218+
return r;
219+
220+
return sd_bus_reply_method_return(message, NULL);
221+
}
222+
185223
const sd_bus_vtable image_vtable[] = {
186224
SD_BUS_VTABLE_START(0),
187225
SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
@@ -198,6 +236,7 @@ const sd_bus_vtable image_vtable[] = {
198236
SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
199237
SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
200238
SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
239+
SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
201240
SD_BUS_VTABLE_END
202241
};
203242

src/machine/image-dbus.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@ int bus_image_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata
3434
int bus_image_method_rename(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
3535
int bus_image_method_clone(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
3636
int bus_image_method_mark_read_only(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
37+
int bus_image_method_set_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);

src/machine/machinectl.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,56 @@ static int cancel_transfer(int argc, char *argv[], void *userdata) {
19611961
return 0;
19621962
}
19631963

1964+
static int set_limit(int argc, char *argv[], void *userdata) {
1965+
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1966+
sd_bus *bus = userdata;
1967+
uint64_t limit;
1968+
int r;
1969+
1970+
if (streq(argv[argc-1], "-"))
1971+
limit = (uint64_t) -1;
1972+
else {
1973+
off_t off;
1974+
1975+
r = parse_size(argv[argc-1], 1024, &off);
1976+
if (r < 0)
1977+
return log_error("Failed to parse size: %s", argv[argc-1]);
1978+
1979+
limit = (uint64_t) off;
1980+
}
1981+
1982+
if (argc > 2)
1983+
/* With two arguments changes the quota limit of the
1984+
* specified image */
1985+
r = sd_bus_call_method(
1986+
bus,
1987+
"org.freedesktop.machine1",
1988+
"/org/freedesktop/machine1",
1989+
"org.freedesktop.machine1.Manager",
1990+
"SetImageLimit",
1991+
&error,
1992+
NULL,
1993+
"st", argv[1], limit);
1994+
else
1995+
/* With one argument changes the pool quota limit */
1996+
r = sd_bus_call_method(
1997+
bus,
1998+
"org.freedesktop.machine1",
1999+
"/org/freedesktop/machine1",
2000+
"org.freedesktop.machine1.Manager",
2001+
"SetPoolLimit",
2002+
&error,
2003+
NULL,
2004+
"t", limit);
2005+
2006+
if (r < 0) {
2007+
log_error("Could not set limit: %s", bus_error_message(&error, -r));
2008+
return r;
2009+
}
2010+
2011+
return 0;
2012+
}
2013+
19642014
static int help(int argc, char *argv[], void *userdata) {
19652015

19662016
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
@@ -2012,7 +2062,8 @@ static int help(int argc, char *argv[], void *userdata) {
20122062
" clone NAME NAME Clone an image\n"
20132063
" rename NAME NAME Rename an image\n"
20142064
" read-only NAME [BOOL] Mark or unmark image read-only\n"
2015-
" remove NAME... Remove an image\n\n"
2065+
" remove NAME... Remove an image\n"
2066+
" set-limit [NAME] BYTES Set image size limit (quota)\n\n"
20162067
"Image Transfer Commands:\n"
20172068
" pull-tar URL [NAME] Download a TAR container image\n"
20182069
" 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) {
22212272
{ "pull-dkr", 2, 3, 0, pull_dkr },
22222273
{ "list-transfers", VERB_ANY, 1, 0, list_transfers },
22232274
{ "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
2275+
{ "set-limit", 2, 3, 0, set_limit },
22242276
{}
22252277
};
22262278

src/machine/machined-dbus.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,61 @@ static int method_mark_image_read_only(sd_bus *bus, sd_bus_message *message, voi
776776
return bus_image_method_mark_read_only(bus, message, i, error);
777777
}
778778

779+
static int method_set_pool_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
780+
Manager *m = userdata;
781+
uint64_t limit;
782+
int r;
783+
784+
assert(bus);
785+
r = sd_bus_message_read(message, "t", &limit);
786+
if (r < 0)
787+
return r;
788+
789+
r = bus_verify_polkit_async(
790+
message,
791+
CAP_SYS_ADMIN,
792+
"org.freedesktop.machine1.manage-machines",
793+
false,
794+
UID_INVALID,
795+
&m->polkit_registry,
796+
error);
797+
if (r < 0)
798+
return r;
799+
if (r == 0)
800+
return 1; /* Will call us back */
801+
802+
r = btrfs_quota_limit("/var/lib/machines", limit);
803+
if (r == -ENOTTY)
804+
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
805+
else if (r < 0)
806+
return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
807+
808+
return sd_bus_reply_method_return(message, NULL);
809+
}
810+
811+
static int method_set_image_limit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
812+
_cleanup_(image_unrefp) Image *i = NULL;
813+
const char *name;
814+
int r;
815+
816+
assert(bus);
817+
r = sd_bus_message_read(message, "s", &name);
818+
if (r < 0)
819+
return r;
820+
821+
if (!image_name_is_valid(name))
822+
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
823+
824+
r = image_find(name, &i);
825+
if (r < 0)
826+
return r;
827+
if (r == 0)
828+
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
829+
830+
i->userdata = userdata;
831+
return bus_image_method_set_limit(bus, message, i, error);
832+
}
833+
779834
const sd_bus_vtable manager_vtable[] = {
780835
SD_BUS_VTABLE_START(0),
781836
SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
@@ -803,6 +858,8 @@ const sd_bus_vtable manager_vtable[] = {
803858
SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
804859
SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
805860
SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
861+
SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
862+
SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
806863
SD_BUS_SIGNAL("MachineNew", "so", 0),
807864
SD_BUS_SIGNAL("MachineRemoved", "so", 0),
808865
SD_BUS_VTABLE_END

src/machine/org.freedesktop.machine1.conf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@
104104
send_interface="org.freedesktop.machine1.Manager"
105105
send_member="MarkImageReadOnly"/>
106106

107+
<allow send_destination="org.freedesktop.machine1"
108+
send_interface="org.freedesktop.machine1.Manager"
109+
send_member="SetPoolLimit"/>
110+
111+
<allow send_destination="org.freedesktop.machine1"
112+
send_interface="org.freedesktop.machine1.Manager"
113+
send_member="SetImageLimit"/>
114+
107115
<allow send_destination="org.freedesktop.machine1"
108116
send_interface="org.freedesktop.machine1.Machine"
109117
send_member="GetAddresses"/>
@@ -148,6 +156,10 @@
148156
send_interface="org.freedesktop.machine1.Image"
149157
send_member="Clone"/>
150158

159+
<allow send_destination="org.freedesktop.machine1"
160+
send_interface="org.freedesktop.machine1.Image"
161+
send_member="SetLimit"/>
162+
151163
<allow send_destination="org.freedesktop.machine1"
152164
send_interface="org.freedesktop.machine1.Image"
153165
send_member="MarkReadOnly"/>

src/shared/btrfs-util.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,3 +669,29 @@ int btrfs_quota_enable(const char *path, bool b) {
669669

670670
return btrfs_quota_enable_fd(fd, b);
671671
}
672+
673+
int btrfs_quota_limit_fd(int fd, uint64_t referred_max) {
674+
struct btrfs_ioctl_qgroup_limit_args args = {
675+
.lim.max_rfer =
676+
referred_max == (uint64_t) -1 ? 0 :
677+
referred_max == 0 ? 1 : referred_max,
678+
.lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER,
679+
};
680+
681+
assert(fd >= 0);
682+
683+
if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0)
684+
return -errno;
685+
686+
return 0;
687+
}
688+
689+
int btrfs_quota_limit(const char *path, uint64_t referred_max) {
690+
_cleanup_close_ int fd = -1;
691+
692+
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
693+
if (fd < 0)
694+
return -errno;
695+
696+
return btrfs_quota_limit_fd(fd, referred_max);
697+
}

src/shared/btrfs-util.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,6 @@ int btrfs_defrag(const char *p);
6767

6868
int btrfs_quota_enable_fd(int fd, bool b);
6969
int btrfs_quota_enable(const char *path, bool b);
70+
71+
int btrfs_quota_limit_fd(int fd, uint64_t referred_max);
72+
int btrfs_quota_limit(const char *path, uint64_t referred_max);

src/shared/machine-image.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,19 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
613613
return 0;
614614
}
615615

616+
int image_set_limit(Image *i, uint64_t referred_max) {
617+
assert(i);
618+
619+
if (path_equal(i->path, "/") ||
620+
path_startswith(i->path, "/usr"))
621+
return -EROFS;
622+
623+
if (i->type != IMAGE_SUBVOLUME)
624+
return -ENOTSUP;
625+
626+
return btrfs_quota_limit(i->path, referred_max);
627+
}
628+
616629
int image_name_lock(const char *name, int operation, LockFile *ret) {
617630
const char *p;
618631

src/shared/machine-image.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,5 @@ bool image_name_is_valid(const char *s) _pure_;
7070

7171
int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local);
7272
int image_name_lock(const char *name, int operation, LockFile *ret);
73+
74+
int image_set_limit(Image *i, uint64_t referred_max);

0 commit comments

Comments
 (0)