Merge pull request #1641 from poettering/btrfs-quota
btrfs quota beef up and various other unrelated changes
This commit is contained in:
@@ -26,6 +26,8 @@ External:
|
||||
|
||||
Features:
|
||||
|
||||
* do something about "/control" subcgroups in the unified cgroup hierarchy
|
||||
|
||||
* when we detect that there are waiting jobs but no running jobs, do something
|
||||
|
||||
* push CPUAffinity also into the "cpuset" cgroup controller
|
||||
@@ -136,9 +138,6 @@ Features:
|
||||
|
||||
* .timer units should optionally support CLOCK_BOOTTIME in addition to CLOCK_MONOTONIC
|
||||
|
||||
* create a btrfs qgroup for /var/lib/machines, and add all container
|
||||
subvolumes we create to it.
|
||||
|
||||
* When logging about multiple units (stopping BoundTo units, conflicts, etc.),
|
||||
log both units as UNIT=, so that journalctl -u triggers on both.
|
||||
|
||||
|
||||
+81
-11
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*-nxml-*-->
|
||||
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
@@ -172,7 +171,77 @@
|
||||
<listitem><para>Create a subvolume if the path does not
|
||||
exist yet and the file system supports this
|
||||
(btrfs). Otherwise create a normal directory, in the same
|
||||
way as <varname>d</varname>.</para></listitem>
|
||||
way as <varname>d</varname>. A subvolume created with this
|
||||
line type is not assigned to any higher-level quota
|
||||
group. For that use <varname>q</varname> or
|
||||
<varname>Q</varname> which allow creating simple quota group
|
||||
hierarchies, see below.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>q</varname></term>
|
||||
<listitem><para>Similar to <varname>v</varname>, however
|
||||
makes sure that the subvolume will be assigned to the same
|
||||
higher-level quota groups as the subvolume it has been
|
||||
created in. This ensures that higher-level limits and
|
||||
accounting applied to the parent subvolume also include the
|
||||
specified subvolume. On non-btrfs file systems, this line
|
||||
type is identical to <varname>d</varname>. If the subvolume
|
||||
already exists and is already assigned to one or more higher
|
||||
level quota groups no change to the quota hierarchy is
|
||||
made. Also see <varname>Q</varname> below. See <citerefentry
|
||||
project='die-net'><refentrytitle>btrfs-qgroup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
for details about the btrfs quota group
|
||||
concept.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Q</varname></term>
|
||||
<listitem><para>Similar to <varname>q</varname>, however
|
||||
instead of copying the higher-level quota group assignments
|
||||
from the parent as-is, the lowest quota group of the parent
|
||||
subvolume is determined that is not the leaf quota
|
||||
group. Then, an "intermediary" quota group is inserted that
|
||||
is one level below this level, and shares the same ID part
|
||||
as the specified subvolume. If no higher-level quota group
|
||||
exists for the parent subvolume, a new quota group at level
|
||||
255 sharing the same ID as the specified subvolume is
|
||||
inserted instead. This new intermediary quota group is then
|
||||
assigned to the parent subvolume's higher-level quota
|
||||
groups, and the specified subvolume's leaf quota group is
|
||||
assigned to it.</para>
|
||||
|
||||
<para>Effectively, this has a similar effect as
|
||||
<varname>q</varname>, however introduces a new higher-level
|
||||
quota group for the specified subvolume that may be used to
|
||||
enforce limits and accounting to the specified subvolume and
|
||||
children subvolume created within it. Thus, by creating
|
||||
subvolumes only via <varname>q</varname> and
|
||||
<varname>Q</varname> a concept of "subtree quotas" is
|
||||
implemented. Each subvolume for which <varname>Q</varname>
|
||||
is set will get a "subtree" quota group created, and all
|
||||
child subvolumes created within it will be assigned to
|
||||
it. Each subvolume for which <varname>q</varname> is set
|
||||
will not get such a "subtree" quota group, but it is ensured
|
||||
that they are added to the same "subtree" quota group as their
|
||||
immediate parents.</para>
|
||||
|
||||
<para>It is recommended to use
|
||||
<varname>Q</varname> for subvolumes that typically contain
|
||||
further subvolumes, and where it is desirable to have
|
||||
accounting and quota limits on all child subvolumes
|
||||
together. Examples for <varname>Q</varname> are typically
|
||||
<filename>/home</filename> or
|
||||
<filename>/var/lib/machines</filename>. In contrast,
|
||||
<varname>q</varname> should be used for subvolumes that
|
||||
either usually do not include further subvolumes or where no
|
||||
accounting and quota limits are needed that apply to all
|
||||
child subvolumes together. Examples for <varname>q</varname>
|
||||
are typically <filename>/var</filename> or
|
||||
<filename>/var/tmp</filename>. As with <varname>Q</varname>,
|
||||
<varname>q</varname> has no effect on the quota group
|
||||
hierarchy if the subvolume exists and already has at least
|
||||
one higher-level quota group assigned.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@@ -504,13 +573,12 @@
|
||||
<para>When the age is set to zero, the files are cleaned
|
||||
unconditionally.</para>
|
||||
|
||||
<para>The age field only applies to lines
|
||||
starting with <varname>d</varname>,
|
||||
<varname>D</varname>, <varname>v</varname>,
|
||||
<varname>C</varname>, <varname>x</varname> and
|
||||
<varname>X</varname>. If omitted or set to
|
||||
<literal>-</literal>, no automatic clean-up is
|
||||
done.</para>
|
||||
<para>The age field only applies to lines starting with
|
||||
<varname>d</varname>, <varname>D</varname>,
|
||||
<varname>v</varname>, <varname>q</varname>,
|
||||
<varname>Q</varname>, <varname>C</varname>, <varname>x</varname>
|
||||
and <varname>X</varname>. If omitted or set to
|
||||
<literal>-</literal>, no automatic clean-up is done.</para>
|
||||
|
||||
<para>If the age field starts with a tilde character
|
||||
<literal>~</literal>, the clean-up is only applied to files and
|
||||
@@ -572,7 +640,9 @@ x /var/tmp/abrt/*</programlisting>
|
||||
<citerefentry project='man-pages'><refentrytitle>setfattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>getfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
<citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry project='die-net'><refentrytitle>btrfs-subvolume</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry project='die-net'><refentrytitle>btrfs-qgroup</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
+852
-53
File diff suppressed because it is too large
Load Diff
+57
-20
@@ -47,25 +47,17 @@ typedef enum BtrfsSnapshotFlags {
|
||||
BTRFS_SNAPSHOT_FALLBACK_COPY = 1,
|
||||
BTRFS_SNAPSHOT_READ_ONLY = 2,
|
||||
BTRFS_SNAPSHOT_RECURSIVE = 4,
|
||||
BTRFS_SNAPSHOT_QUOTA = 8,
|
||||
} BtrfsSnapshotFlags;
|
||||
|
||||
typedef enum BtrfsRemoveFlags {
|
||||
BTRFS_REMOVE_RECURSIVE = 1,
|
||||
BTRFS_REMOVE_QUOTA = 2,
|
||||
} BtrfsRemoveFlags;
|
||||
|
||||
int btrfs_is_filesystem(int fd);
|
||||
int btrfs_is_subvol(int fd);
|
||||
|
||||
int btrfs_subvol_make(const char *path);
|
||||
int btrfs_subvol_make_label(const char *path);
|
||||
|
||||
int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags);
|
||||
int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags);
|
||||
|
||||
int btrfs_subvol_set_read_only_fd(int fd, bool b);
|
||||
int btrfs_subvol_set_read_only(const char *path, bool b);
|
||||
int btrfs_subvol_get_read_only_fd(int fd);
|
||||
int btrfs_subvol_get_id(int fd, const char *subvolume, uint64_t *ret);
|
||||
int btrfs_subvol_get_id_fd(int fd, uint64_t *ret);
|
||||
int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *info);
|
||||
int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *quota);
|
||||
|
||||
int btrfs_reflink(int infd, int outfd);
|
||||
int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz);
|
||||
|
||||
@@ -78,14 +70,59 @@ 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 referenced_max);
|
||||
int btrfs_quota_limit(const char *path, uint64_t referenced_max);
|
||||
int btrfs_quota_scan_start(int fd);
|
||||
int btrfs_quota_scan_wait(int fd);
|
||||
int btrfs_quota_scan_ongoing(int fd);
|
||||
|
||||
int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only);
|
||||
int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only);
|
||||
|
||||
int btrfs_subvol_remove(const char *path, bool recursive);
|
||||
int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive);
|
||||
int btrfs_subvol_make(const char *path);
|
||||
int btrfs_subvol_make_label(const char *path);
|
||||
|
||||
int btrfs_qgroup_create(int fd, uint64_t level, uint64_t id);
|
||||
int btrfs_qgroup_destroy(int fd, uint64_t level, uint64_t id);
|
||||
int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags);
|
||||
int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags);
|
||||
|
||||
int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags);
|
||||
int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags);
|
||||
|
||||
int btrfs_subvol_set_read_only_fd(int fd, bool b);
|
||||
int btrfs_subvol_set_read_only(const char *path, bool b);
|
||||
int btrfs_subvol_get_read_only_fd(int fd);
|
||||
|
||||
int btrfs_subvol_get_id(int fd, const char *subvolume, uint64_t *ret);
|
||||
int btrfs_subvol_get_id_fd(int fd, uint64_t *ret);
|
||||
int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret);
|
||||
|
||||
int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *info);
|
||||
|
||||
int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret);
|
||||
|
||||
int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *quota);
|
||||
int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *quota);
|
||||
|
||||
int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max);
|
||||
int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max);
|
||||
|
||||
int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool new_qgroup);
|
||||
int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup);
|
||||
|
||||
int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret);
|
||||
int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id);
|
||||
|
||||
int btrfs_qgroup_create(int fd, uint64_t qgroupid);
|
||||
int btrfs_qgroup_destroy(int fd, uint64_t qgroupid);
|
||||
int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid);
|
||||
|
||||
int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max);
|
||||
int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max);
|
||||
|
||||
int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid);
|
||||
|
||||
int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent);
|
||||
int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent);
|
||||
|
||||
int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret);
|
||||
|
||||
int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *quota);
|
||||
int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *quota);
|
||||
|
||||
@@ -494,6 +494,10 @@ struct btrfs_ioctl_quota_ctl_args {
|
||||
#define BTRFS_QGROUP_LIMIT_KEY 244
|
||||
#endif
|
||||
|
||||
#ifndef BTRFS_QGROUP_RELATION_KEY
|
||||
#define BTRFS_QGROUP_RELATION_KEY 246
|
||||
#endif
|
||||
|
||||
#ifndef BTRFS_ROOT_BACKREF_KEY
|
||||
#define BTRFS_ROOT_BACKREF_KEY 144
|
||||
#endif
|
||||
|
||||
+18
-5
@@ -796,14 +796,11 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd
|
||||
return changed;
|
||||
}
|
||||
|
||||
int fsck_exists(const char *fstype) {
|
||||
static int binary_is_good(const char *binary) {
|
||||
_cleanup_free_ char *p = NULL, *d = NULL;
|
||||
const char *checker;
|
||||
int r;
|
||||
|
||||
checker = strjoina("fsck.", fstype);
|
||||
|
||||
r = find_binary(checker, true, &p);
|
||||
r = find_binary(binary, true, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -820,6 +817,22 @@ int fsck_exists(const char *fstype) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fsck_exists(const char *fstype) {
|
||||
const char *checker;
|
||||
|
||||
checker = strjoina("fsck.", fstype);
|
||||
|
||||
return binary_is_good(checker);
|
||||
}
|
||||
|
||||
int mkfs_exists(const char *fstype) {
|
||||
const char *mkfs;
|
||||
|
||||
mkfs = strjoina("mkfs.", fstype);
|
||||
|
||||
return binary_is_good(mkfs);
|
||||
}
|
||||
|
||||
char *prefix_root(const char *root, const char *path) {
|
||||
char *n, *p;
|
||||
size_t l;
|
||||
|
||||
@@ -63,6 +63,7 @@ int find_binary(const char *name, bool local, char **filename);
|
||||
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
|
||||
|
||||
int fsck_exists(const char *fstype);
|
||||
int mkfs_exists(const char *fstype);
|
||||
|
||||
/* Iterates through the path prefixes of the specified path, going up
|
||||
* the tree, to root. Also returns "" (and not "/"!) for the root
|
||||
|
||||
+2
-2
@@ -120,7 +120,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
|
||||
|
||||
/* This could be a subvolume, try to remove it */
|
||||
|
||||
r = btrfs_subvol_remove_fd(fd, de->d_name, true);
|
||||
r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
|
||||
if (r < 0) {
|
||||
if (r != -ENOTTY && r != -EINVAL) {
|
||||
if (ret == 0)
|
||||
@@ -178,7 +178,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
|
||||
|
||||
if ((flags & (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) == (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) {
|
||||
/* Try to remove as subvolume first */
|
||||
r = btrfs_subvol_remove(path, true);
|
||||
r = btrfs_subvol_remove(path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
|
||||
|
||||
+4
-13
@@ -2381,25 +2381,16 @@ bool is_device_path(const char *path) {
|
||||
|
||||
int dir_is_empty(const char *path) {
|
||||
_cleanup_closedir_ DIR *d;
|
||||
struct dirent *de;
|
||||
|
||||
d = opendir(path);
|
||||
if (!d)
|
||||
return -errno;
|
||||
|
||||
for (;;) {
|
||||
struct dirent *de;
|
||||
FOREACH_DIRENT(de, d, return -errno)
|
||||
return 0;
|
||||
|
||||
errno = 0;
|
||||
de = readdir(d);
|
||||
if (!de && errno != 0)
|
||||
return -errno;
|
||||
|
||||
if (!de)
|
||||
return 1;
|
||||
|
||||
if (!hidden_file(de->d_name))
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* dirname_malloc(const char *path) {
|
||||
|
||||
@@ -358,6 +358,14 @@ bool is_device_path(const char *path);
|
||||
int dir_is_empty(const char *path);
|
||||
char* dirname_malloc(const char *path);
|
||||
|
||||
static inline int dir_is_populated(const char *path) {
|
||||
int r;
|
||||
r = dir_is_empty(path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
return !r;
|
||||
}
|
||||
|
||||
char* lookup_uid(uid_t uid);
|
||||
char* getlogname_malloc(void);
|
||||
char* getusername_malloc(void);
|
||||
|
||||
@@ -1173,7 +1173,6 @@ int bus_exec_context_set_transient_property(
|
||||
|
||||
unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -1262,6 +1261,10 @@ int bus_exec_context_set_transient_property(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = fflush_and_check(f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1279,10 +1282,6 @@ int bus_exec_context_set_transient_property(
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
|
||||
|
||||
@@ -78,7 +78,7 @@ TarExport *tar_export_unref(TarExport *e) {
|
||||
}
|
||||
|
||||
if (e->temp_path) {
|
||||
(void) btrfs_subvol_remove(e->temp_path, false);
|
||||
(void) btrfs_subvol_remove(e->temp_path, BTRFS_REMOVE_QUOTA);
|
||||
free(e->temp_path);
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType
|
||||
if (e->st.st_ino == 256) { /* might be a btrfs subvolume? */
|
||||
BtrfsQuotaInfo q;
|
||||
|
||||
r = btrfs_subvol_get_quota_fd(sfd, &q);
|
||||
r = btrfs_subvol_get_subtree_quota_fd(sfd, 0, &q);
|
||||
if (r >= 0)
|
||||
e->quota_referenced = q.referenced;
|
||||
|
||||
|
||||
@@ -235,6 +235,8 @@ static int tar_import_fork_tar(TarImport *i) {
|
||||
return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
|
||||
} else if (r < 0)
|
||||
return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
|
||||
else
|
||||
(void) import_assign_pool_quota_and_warn(i->temp_path);
|
||||
|
||||
i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
|
||||
if (i->tar_fd < 0)
|
||||
|
||||
@@ -138,7 +138,7 @@ int pull_make_local_copy(const char *final, const char *image_root, const char *
|
||||
if (force_local)
|
||||
(void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
|
||||
|
||||
r = btrfs_subvol_snapshot(final, p, 0);
|
||||
r = btrfs_subvol_snapshot(final, p, BTRFS_SNAPSHOT_QUOTA);
|
||||
if (r == -ENOTTY) {
|
||||
r = copy_tree(final, p, false);
|
||||
if (r < 0)
|
||||
@@ -366,9 +366,10 @@ int pull_verify(PullJob *main_job,
|
||||
|
||||
log_info("SHA256 checksum of %s is valid.", main_job->url);
|
||||
|
||||
assert(!settings_job || settings_job->state == PULL_JOB_DONE);
|
||||
assert(!settings_job || IN_SET(settings_job->state, PULL_JOB_DONE, PULL_JOB_FAILED));
|
||||
|
||||
if (settings_job &&
|
||||
settings_job->state == PULL_JOB_DONE &&
|
||||
settings_job->error == 0 &&
|
||||
!settings_job->etag_exists) {
|
||||
|
||||
|
||||
+12
-4
@@ -490,10 +490,16 @@ static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) {
|
||||
return r;
|
||||
|
||||
if (version == DKR_PULL_V2) {
|
||||
char **k = NULL;
|
||||
char **k;
|
||||
|
||||
STRV_FOREACH(k, i->ancestry) {
|
||||
_cleanup_free_ char *d = strjoin(i->image_root, "/.dkr-", *k, NULL);
|
||||
r = btrfs_subvol_remove(d, false);
|
||||
_cleanup_free_ char *d;
|
||||
|
||||
d = strjoin(i->image_root, "/.dkr-", *k, NULL);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
r = btrfs_subvol_remove(d, BTRFS_REMOVE_QUOTA);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@@ -531,12 +537,14 @@ static int dkr_pull_job_on_open_disk(PullJob *j) {
|
||||
const char *base_path;
|
||||
|
||||
base_path = strjoina(i->image_root, "/.dkr-", base);
|
||||
r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY);
|
||||
r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY|BTRFS_SNAPSHOT_QUOTA);
|
||||
} else
|
||||
r = btrfs_subvol_make(i->temp_path);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path);
|
||||
|
||||
(void) import_assign_pool_quota_and_warn(i->temp_path);
|
||||
|
||||
j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
|
||||
if (j->disk_fd < 0)
|
||||
return j->disk_fd;
|
||||
|
||||
@@ -349,9 +349,9 @@ static int raw_pull_make_local_copy(RawPull *i) {
|
||||
if (r == -EEXIST)
|
||||
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
|
||||
else if (r < 0 && r != -ENOENT)
|
||||
log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings);
|
||||
|
||||
log_info("Create new settings file '%s.nspawn'", i->local);
|
||||
log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
|
||||
else
|
||||
log_info("Created new settings file '%s.nspawn'", i->local);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -247,9 +247,9 @@ static int tar_pull_make_local_copy(TarPull *i) {
|
||||
if (r == -EEXIST)
|
||||
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
|
||||
else if (r < 0 && r != -ENOENT)
|
||||
log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings);
|
||||
|
||||
log_info("Create new settings file '%s.nspawn'", i->local);
|
||||
log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
|
||||
else
|
||||
log_info("Created new settings file '%s.nspawn'", i->local);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -410,6 +410,8 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
|
||||
return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
|
||||
} else if (r < 0)
|
||||
return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
|
||||
else
|
||||
(void) import_assign_pool_quota_and_warn(i->temp_path);
|
||||
|
||||
j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
|
||||
if (j->disk_fd < 0)
|
||||
|
||||
@@ -1049,9 +1049,13 @@ error:
|
||||
}
|
||||
|
||||
void session_restore_vt(Session *s) {
|
||||
|
||||
static const struct vt_mode mode = {
|
||||
.mode = VT_AUTO,
|
||||
};
|
||||
|
||||
_cleanup_free_ char *utf8 = NULL;
|
||||
int vt, kb = K_XLATE;
|
||||
struct vt_mode mode = { 0 };
|
||||
int vt, kb, old_fd;
|
||||
|
||||
/* We need to get a fresh handle to the virtual terminal,
|
||||
* since the old file-descriptor is potentially in a hung-up
|
||||
@@ -1059,7 +1063,7 @@ void session_restore_vt(Session *s) {
|
||||
* little dance to avoid having the terminal be available
|
||||
* for reuse before we've cleaned it up.
|
||||
*/
|
||||
int old_fd = s->vtfd;
|
||||
old_fd = s->vtfd;
|
||||
s->vtfd = -1;
|
||||
|
||||
vt = session_open_vt(s);
|
||||
@@ -1072,13 +1076,13 @@ void session_restore_vt(Session *s) {
|
||||
|
||||
if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
|
||||
kb = K_UNICODE;
|
||||
else
|
||||
kb = K_XLATE;
|
||||
|
||||
(void) ioctl(vt, KDSKBMODE, kb);
|
||||
|
||||
mode.mode = VT_AUTO;
|
||||
(void) ioctl(vt, VT_SETMODE, &mode);
|
||||
|
||||
fchown(vt, 0, -1);
|
||||
(void) fchown(vt, 0, (gid_t) -1);
|
||||
|
||||
s->vtfd = safe_close(s->vtfd);
|
||||
}
|
||||
|
||||
@@ -2382,7 +2382,7 @@ static int set_limit(int argc, char *argv[], void *userdata) {
|
||||
uint64_t limit;
|
||||
int r;
|
||||
|
||||
if (streq(argv[argc-1], "-"))
|
||||
if (STR_IN_SET(argv[argc-1], "-", "none", "infinity"))
|
||||
limit = (uint64_t) -1;
|
||||
else {
|
||||
r = parse_size(argv[argc-1], 1024, &limit);
|
||||
|
||||
@@ -79,7 +79,7 @@ static int property_get_pool_usage(
|
||||
if (fd >= 0) {
|
||||
BtrfsQuotaInfo q;
|
||||
|
||||
if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
|
||||
if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
|
||||
usage = q.referenced;
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ static int property_get_pool_limit(
|
||||
if (fd >= 0) {
|
||||
BtrfsQuotaInfo q;
|
||||
|
||||
if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
|
||||
if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
|
||||
size = q.referenced_max;
|
||||
}
|
||||
|
||||
@@ -831,7 +831,9 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
|
||||
if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
|
||||
|
||||
r = btrfs_quota_limit("/var/lib/machines", limit);
|
||||
(void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit);
|
||||
|
||||
r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit);
|
||||
if (r == -ENOTTY)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
|
||||
if (r < 0)
|
||||
|
||||
@@ -85,6 +85,26 @@ Settings* settings_free(Settings *s) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool settings_private_network(Settings *s) {
|
||||
assert(s);
|
||||
|
||||
return
|
||||
s->private_network > 0 ||
|
||||
s->network_veth > 0 ||
|
||||
s->network_bridge ||
|
||||
s->network_interfaces ||
|
||||
s->network_macvlan ||
|
||||
s->network_ipvlan;
|
||||
}
|
||||
|
||||
bool settings_network_veth(Settings *s) {
|
||||
assert(s);
|
||||
|
||||
return
|
||||
s->network_veth > 0 ||
|
||||
s->network_bridge;
|
||||
}
|
||||
|
||||
DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode");
|
||||
|
||||
int config_parse_expose_port(
|
||||
|
||||
@@ -75,6 +75,9 @@ typedef struct Settings {
|
||||
int settings_load(FILE *f, const char *path, Settings **ret);
|
||||
Settings* settings_free(Settings *s);
|
||||
|
||||
bool settings_network_veth(Settings *s);
|
||||
bool settings_private_network(Settings *s);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Settings*, settings_free);
|
||||
|
||||
const struct ConfigPerfItem* nspawn_gperf_lookup(const char *key, unsigned length);
|
||||
|
||||
+19
-15
@@ -2912,11 +2912,17 @@ static int load_settings(void) {
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_CAPABILITY) == 0) {
|
||||
uint64_t plus;
|
||||
|
||||
if (!arg_settings_trusted && settings->capability != 0)
|
||||
log_warning("Ignoring Capability= setting, file %s is not trusted.", p);
|
||||
else
|
||||
arg_retain |= settings->capability;
|
||||
plus = settings->capability;
|
||||
if (settings_private_network(settings))
|
||||
plus |= (1ULL << CAP_NET_ADMIN);
|
||||
|
||||
if (!arg_settings_trusted && plus != 0) {
|
||||
if (settings->capability != 0)
|
||||
log_warning("Ignoring Capability= setting, file %s is not trusted.", p);
|
||||
} else
|
||||
arg_retain |= plus;
|
||||
|
||||
arg_retain &= ~settings->drop_capability;
|
||||
}
|
||||
@@ -2972,6 +2978,9 @@ static int load_settings(void) {
|
||||
if (!arg_settings_trusted)
|
||||
log_warning("Ignoring network settings, file %s is not trusted.", p);
|
||||
else {
|
||||
arg_network_veth = settings_private_network(settings);
|
||||
arg_private_network = settings_private_network(settings);
|
||||
|
||||
strv_free(arg_network_interfaces);
|
||||
arg_network_interfaces = settings->network_interfaces;
|
||||
settings->network_interfaces = NULL;
|
||||
@@ -2987,10 +2996,6 @@ static int load_settings(void) {
|
||||
free(arg_network_bridge);
|
||||
arg_network_bridge = settings->network_bridge;
|
||||
settings->network_bridge = NULL;
|
||||
|
||||
arg_network_veth = settings->network_veth > 0 || settings->network_bridge;
|
||||
|
||||
arg_private_network = true; /* all these settings imply private networking */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3096,7 +3101,7 @@ int main(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
|
||||
r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory);
|
||||
goto finish;
|
||||
@@ -3120,7 +3125,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
if (arg_template) {
|
||||
r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
|
||||
r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
|
||||
if (r == -EEXIST) {
|
||||
if (!arg_quiet)
|
||||
log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template);
|
||||
@@ -3143,10 +3148,9 @@ int main(int argc, char *argv[]) {
|
||||
} else {
|
||||
const char *p;
|
||||
|
||||
p = strjoina(arg_directory,
|
||||
argc > optind && path_is_absolute(argv[optind]) ? argv[optind] : "/usr/bin/");
|
||||
if (access(p, F_OK) < 0) {
|
||||
log_error("Directory %s lacks the binary to execute or doesn't look like a binary tree. Refusing.", arg_directory);
|
||||
p = strjoina(arg_directory, "/usr/");
|
||||
if (laccess(p, F_OK) < 0) {
|
||||
log_error("Directory %s doesn't look like it has an OS tree. Refusing.", arg_directory);
|
||||
r = -EINVAL;
|
||||
goto finish;
|
||||
}
|
||||
@@ -3591,7 +3595,7 @@ finish:
|
||||
if (remove_subvol && arg_directory) {
|
||||
int k;
|
||||
|
||||
k = btrfs_subvol_remove(arg_directory, true);
|
||||
k = btrfs_subvol_remove(arg_directory, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
|
||||
if (k < 0)
|
||||
log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "btrfs-util.h"
|
||||
#include "util.h"
|
||||
#include "import-util.h"
|
||||
|
||||
@@ -201,3 +202,29 @@ bool dkr_id_is_valid(const char *id) {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int import_assign_pool_quota_and_warn(const char *path) {
|
||||
int r;
|
||||
|
||||
r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true);
|
||||
if (r == -ENOTTY) {
|
||||
log_debug_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, as directory is not on btrfs or not a subvolume. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines: %m");
|
||||
if (r > 0)
|
||||
log_info("Set up default quota hierarchy for /var/lib/machines.");
|
||||
|
||||
r = btrfs_subvol_auto_qgroup(path, 0, true);
|
||||
if (r == -ENOTTY) {
|
||||
log_debug_errno(r, "Failed to set up quota hierarchy for %s, as directory is not on btrfs or not a subvolume. Ignoring.", path);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set up default quota hierarchy for %s: %m", path);
|
||||
if (r > 0)
|
||||
log_info("Set up default quota hierarchy for %s.", path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -47,3 +47,5 @@ bool dkr_id_is_valid(const char *id);
|
||||
bool dkr_ref_is_valid(const char *ref);
|
||||
bool dkr_digest_is_valid(const char *digest);
|
||||
#define dkr_tag_is_valid(tag) filename_is_valid(tag)
|
||||
|
||||
int import_assign_pool_quota_and_warn(const char *path);
|
||||
|
||||
+30
-11
@@ -176,11 +176,10 @@ static int image_make(
|
||||
return r;
|
||||
if (r) {
|
||||
BtrfsSubvolInfo info;
|
||||
BtrfsQuotaInfo quota;
|
||||
|
||||
/* It's a btrfs subvolume */
|
||||
|
||||
r = btrfs_subvol_get_info_fd(fd, &info);
|
||||
r = btrfs_subvol_get_info_fd(fd, 0, &info);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -195,13 +194,17 @@ static int image_make(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = btrfs_subvol_get_quota_fd(fd, "a);
|
||||
if (r >= 0) {
|
||||
(*ret)->usage = quota.referenced;
|
||||
(*ret)->usage_exclusive = quota.exclusive;
|
||||
if (btrfs_quota_scan_ongoing(fd) == 0) {
|
||||
BtrfsQuotaInfo quota;
|
||||
|
||||
(*ret)->limit = quota.referenced_max;
|
||||
(*ret)->limit_exclusive = quota.exclusive_max;
|
||||
r = btrfs_subvol_get_subtree_quota_fd(fd, 0, "a);
|
||||
if (r >= 0) {
|
||||
(*ret)->usage = quota.referenced;
|
||||
(*ret)->usage_exclusive = quota.exclusive;
|
||||
|
||||
(*ret)->limit = quota.referenced_max;
|
||||
(*ret)->limit_exclusive = quota.exclusive_max;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
@@ -397,7 +400,7 @@ int image_remove(Image *i) {
|
||||
switch (i->type) {
|
||||
|
||||
case IMAGE_SUBVOLUME:
|
||||
r = btrfs_subvol_remove(i->path, true);
|
||||
r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
@@ -587,7 +590,12 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
|
||||
case IMAGE_DIRECTORY:
|
||||
new_path = strjoina("/var/lib/machines/", new_name);
|
||||
|
||||
r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
|
||||
r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
|
||||
|
||||
/* Enable "subtree" quotas for the copy, if we didn't
|
||||
* copy any quota from the source. */
|
||||
(void) btrfs_subvol_auto_qgroup(i->path, 0, true);
|
||||
|
||||
break;
|
||||
|
||||
case IMAGE_RAW:
|
||||
@@ -629,6 +637,10 @@ int image_read_only(Image *i, bool b) {
|
||||
switch (i->type) {
|
||||
|
||||
case IMAGE_SUBVOLUME:
|
||||
|
||||
/* Note that we set the flag only on the top-level
|
||||
* subvolume of the image. */
|
||||
|
||||
r = btrfs_subvol_set_read_only(i->path, b);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -729,7 +741,14 @@ int image_set_limit(Image *i, uint64_t referenced_max) {
|
||||
if (i->type != IMAGE_SUBVOLUME)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return btrfs_quota_limit(i->path, referenced_max);
|
||||
/* We set the quota both for the subvolume as well as for the
|
||||
* subtree. The latter is mostly for historical reasons, since
|
||||
* we didn't use to have a concept of subtree quota, and hence
|
||||
* only modified the subvolume quota. */
|
||||
|
||||
(void) btrfs_qgroup_set_limit(i->path, 0, referenced_max);
|
||||
(void) btrfs_subvol_auto_qgroup(i->path, 0, true);
|
||||
return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max);
|
||||
}
|
||||
|
||||
int image_name_lock(const char *name, int operation, LockFile *ret) {
|
||||
|
||||
@@ -170,7 +170,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
|
||||
};
|
||||
_cleanup_close_ int fd = -1, control = -1, loop = -1;
|
||||
_cleanup_free_ char* loopdev = NULL;
|
||||
char tmpdir[] = "/tmp/import-mount.XXXXXX", *mntdir = NULL;
|
||||
char tmpdir[] = "/tmp/machine-pool.XXXXXX", *mntdir = NULL;
|
||||
bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false;
|
||||
char buf[FORMAT_BYTES_MAX];
|
||||
int r, nr = -1;
|
||||
@@ -194,14 +194,35 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
|
||||
|
||||
r = btrfs_quota_enable("/var/lib/machines", true);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to enable quota, ignoring: %m");
|
||||
log_warning_errno(r, "Failed to enable quota for /var/lib/machines, ignoring: %m");
|
||||
|
||||
r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, ignoring: %m");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0) {
|
||||
log_debug("/var/lib/machines is already a mount point, not creating loopback file for it.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0 ||
|
||||
dir_is_empty("/var/lib/machines") == 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "/var/lib/machines is not a btrfs file system. Operation is not supported on legacy file systems.");
|
||||
r = dir_is_populated("/var/lib/machines");
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
log_debug("/var/log/machines is already populated, not creating loopback file for it.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = mkfs_exists("btrfs");
|
||||
if (r == -ENOENT) {
|
||||
log_debug("mkfs.btrfs is missing, cannot create loopback file for /var/lib/machines.");
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
fd = setup_machine_raw(size, error);
|
||||
if (fd < 0)
|
||||
@@ -266,6 +287,10 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to enable quota, ignoring: %m");
|
||||
|
||||
r = btrfs_subvol_auto_qgroup(mntdir, 0, true);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to set up default quota hierarchy, ignoring: %m");
|
||||
|
||||
if (chmod(mntdir, 0700) < 0) {
|
||||
r = sd_bus_error_set_errnof(error, errno, "Failed to fix owner: %m");
|
||||
goto fail;
|
||||
@@ -286,7 +311,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
|
||||
(void) rmdir(mntdir);
|
||||
(void) rmdir(tmpdir);
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
if (mntdir_mounted)
|
||||
@@ -370,9 +395,11 @@ int grow_machine_directory(void) {
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = btrfs_quota_limit("/var/lib/machines", new_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
/* Also bump the quota, of both the subvolume leaf qgroup, as
|
||||
* well as of any subtree quota group by the same id but a
|
||||
* higher level, if it exists. */
|
||||
(void) btrfs_qgroup_set_limit("/var/lib/machines", 0, new_size);
|
||||
(void) btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, new_size);
|
||||
|
||||
log_info("Grew /var/lib/machines btrfs loopback file system to %s.", format_bytes(buf, sizeof(buf), new_size));
|
||||
return 1;
|
||||
|
||||
@@ -7399,12 +7399,12 @@ static int talk_initctl(void) {
|
||||
static int systemctl_main(int argc, char *argv[]) {
|
||||
|
||||
static const Verb verbs[] = {
|
||||
{ "list-units", VERB_ANY, 1, VERB_DEFAULT, list_units },
|
||||
{ "list-unit-files", VERB_ANY, 1, 0, list_unit_files },
|
||||
{ "list-sockets", VERB_ANY, 1, 0, list_sockets },
|
||||
{ "list-timers", VERB_ANY, 1, 0, list_timers },
|
||||
{ "list-jobs", VERB_ANY, 1, 0, list_jobs },
|
||||
{ "list-machines", VERB_ANY, 1, 0, list_machines },
|
||||
{ "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_units },
|
||||
{ "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
|
||||
{ "list-sockets", VERB_ANY, VERB_ANY, 0, list_sockets },
|
||||
{ "list-timers", VERB_ANY, VERB_ANY, 0, list_timers },
|
||||
{ "list-jobs", VERB_ANY, VERB_ANY, 0, list_jobs },
|
||||
{ "list-machines", VERB_ANY, VERB_ANY, 0, list_machines },
|
||||
{ "clear-jobs", VERB_ANY, 1, 0, daemon_reload },
|
||||
{ "cancel", 2, VERB_ANY, 0, cancel_job },
|
||||
{ "start", 2, VERB_ANY, 0, start_unit },
|
||||
|
||||
+58
-10
@@ -27,17 +27,17 @@
|
||||
#include "btrfs-util.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
BtrfsQuotaInfo quota;
|
||||
int r, fd;
|
||||
|
||||
fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
|
||||
if (fd < 0)
|
||||
log_error_errno(errno, "Failed to open root directory: %m");
|
||||
else {
|
||||
BtrfsSubvolInfo info;
|
||||
BtrfsQuotaInfo quota;
|
||||
char ts[FORMAT_TIMESTAMP_MAX], bs[FORMAT_BYTES_MAX];
|
||||
BtrfsSubvolInfo info;
|
||||
|
||||
r = btrfs_subvol_get_info_fd(fd, &info);
|
||||
r = btrfs_subvol_get_info_fd(fd, 0, &info);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to get subvolume info: %m");
|
||||
else {
|
||||
@@ -45,7 +45,7 @@ int main(int argc, char *argv[]) {
|
||||
log_info("read-only (search): %s", yes_no(info.read_only));
|
||||
}
|
||||
|
||||
r = btrfs_subvol_get_quota_fd(fd, "a);
|
||||
r = btrfs_qgroup_get_quota_fd(fd, 0, "a);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to get quota info: %m");
|
||||
else {
|
||||
@@ -80,15 +80,15 @@ int main(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make snapshot: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxtest", false);
|
||||
r = btrfs_subvol_remove("/xxxtest", BTRFS_REMOVE_QUOTA);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxtest2", false);
|
||||
r = btrfs_subvol_remove("/xxxtest2", BTRFS_REMOVE_QUOTA);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxtest3", false);
|
||||
r = btrfs_subvol_remove("/xxxtest3", BTRFS_REMOVE_QUOTA);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
|
||||
@@ -96,7 +96,7 @@ int main(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make snapshot: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/etc2", false);
|
||||
r = btrfs_subvol_remove("/etc2", BTRFS_REMOVE_QUOTA);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to remove subvolume: %m");
|
||||
|
||||
@@ -137,13 +137,61 @@ int main(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to snapshot subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxrectest", true);
|
||||
r = btrfs_subvol_remove("/xxxrectest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to recursively remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxrectest2", true);
|
||||
r = btrfs_subvol_remove("/xxxrectest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to recursively remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_make("/xxxquotatest");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_auto_qgroup("/xxxquotatest", 0, true);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to set up auto qgroup: %m");
|
||||
|
||||
r = btrfs_subvol_make("/xxxquotatest/beneath");
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to make subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_auto_qgroup("/xxxquotatest/beneath", 0, false);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to set up auto qgroup: %m");
|
||||
|
||||
r = btrfs_qgroup_set_limit("/xxxquotatest/beneath", 0, 4ULL * 1024 * 1024 * 1024);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to set up quota limit: %m");
|
||||
|
||||
r = btrfs_subvol_set_subtree_quota_limit("/xxxquotatest", 0, 5ULL * 1024 * 1024 * 1024);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to set up quota limit: %m");
|
||||
|
||||
r = btrfs_subvol_snapshot("/xxxquotatest", "/xxxquotatest2", BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to setup snapshot: %m");
|
||||
|
||||
r = btrfs_qgroup_get_quota("/xxxquotatest2/beneath", 0, "a);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to query quota: %m");
|
||||
|
||||
assert_se(quota.referenced_max == 4ULL * 1024 * 1024 * 1024);
|
||||
|
||||
r = btrfs_subvol_get_subtree_quota("/xxxquotatest2", 0, "a);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to query quota: %m");
|
||||
|
||||
assert_se(quota.referenced_max == 5ULL * 1024 * 1024 * 1024);
|
||||
|
||||
r = btrfs_subvol_remove("/xxxquotatest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed remove subvolume: %m");
|
||||
|
||||
r = btrfs_subvol_remove("/xxxquotatest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed remove subvolume: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+35
-8
@@ -69,6 +69,8 @@ typedef enum ItemType {
|
||||
CREATE_DIRECTORY = 'd',
|
||||
TRUNCATE_DIRECTORY = 'D',
|
||||
CREATE_SUBVOLUME = 'v',
|
||||
CREATE_SUBVOLUME_INHERIT_QUOTA = 'q',
|
||||
CREATE_SUBVOLUME_NEW_QUOTA = 'Q',
|
||||
CREATE_FIFO = 'p',
|
||||
CREATE_SYMLINK = 'L',
|
||||
CREATE_CHAR_DEVICE = 'c',
|
||||
@@ -180,6 +182,8 @@ static bool takes_ownership(ItemType t) {
|
||||
CREATE_DIRECTORY,
|
||||
TRUNCATE_DIRECTORY,
|
||||
CREATE_SUBVOLUME,
|
||||
CREATE_SUBVOLUME_INHERIT_QUOTA,
|
||||
CREATE_SUBVOLUME_NEW_QUOTA,
|
||||
CREATE_FIFO,
|
||||
CREATE_SYMLINK,
|
||||
CREATE_CHAR_DEVICE,
|
||||
@@ -1198,16 +1202,16 @@ static int create_item(Item *i) {
|
||||
case CREATE_DIRECTORY:
|
||||
case TRUNCATE_DIRECTORY:
|
||||
case CREATE_SUBVOLUME:
|
||||
case CREATE_SUBVOLUME_INHERIT_QUOTA:
|
||||
case CREATE_SUBVOLUME_NEW_QUOTA:
|
||||
|
||||
RUN_WITH_UMASK(0000)
|
||||
mkdir_parents_label(i->path, 0755);
|
||||
|
||||
if (i->type == CREATE_SUBVOLUME)
|
||||
RUN_WITH_UMASK((~i->mode) & 0777) {
|
||||
if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) {
|
||||
RUN_WITH_UMASK((~i->mode) & 0777)
|
||||
r = btrfs_subvol_make(i->path);
|
||||
log_debug_errno(r, "Creating subvolume \"%s\": %m", i->path);
|
||||
}
|
||||
else
|
||||
} else
|
||||
r = 0;
|
||||
|
||||
if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY)
|
||||
@@ -1236,6 +1240,24 @@ static int create_item(Item *i) {
|
||||
|
||||
log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path);
|
||||
|
||||
if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
|
||||
r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
|
||||
if (r == -ENOTTY) {
|
||||
log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i->path);
|
||||
return 0;
|
||||
}
|
||||
if (r == -EROFS) {
|
||||
log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i->path);
|
||||
return 0;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
|
||||
if (r > 0)
|
||||
log_debug("Adjusted quota for subvolume \"%s\".", i->path);
|
||||
if (r == 0)
|
||||
log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
|
||||
}
|
||||
|
||||
r = path_set_perms(i, i->path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -1492,6 +1514,8 @@ static int remove_item(Item *i) {
|
||||
case TRUNCATE_FILE:
|
||||
case CREATE_DIRECTORY:
|
||||
case CREATE_SUBVOLUME:
|
||||
case CREATE_SUBVOLUME_INHERIT_QUOTA:
|
||||
case CREATE_SUBVOLUME_NEW_QUOTA:
|
||||
case CREATE_FIFO:
|
||||
case CREATE_SYMLINK:
|
||||
case CREATE_CHAR_DEVICE:
|
||||
@@ -1583,6 +1607,8 @@ static int clean_item(Item *i) {
|
||||
switch (i->type) {
|
||||
case CREATE_DIRECTORY:
|
||||
case CREATE_SUBVOLUME:
|
||||
case CREATE_SUBVOLUME_INHERIT_QUOTA:
|
||||
case CREATE_SUBVOLUME_NEW_QUOTA:
|
||||
case TRUNCATE_DIRECTORY:
|
||||
case IGNORE_PATH:
|
||||
case COPY_FILES:
|
||||
@@ -1819,6 +1845,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
||||
|
||||
case CREATE_DIRECTORY:
|
||||
case CREATE_SUBVOLUME:
|
||||
case CREATE_SUBVOLUME_INHERIT_QUOTA:
|
||||
case CREATE_SUBVOLUME_NEW_QUOTA:
|
||||
case TRUNCATE_DIRECTORY:
|
||||
case CREATE_FIFO:
|
||||
case IGNORE_PATH:
|
||||
@@ -1983,8 +2011,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
||||
i.mode = m;
|
||||
i.mode_set = true;
|
||||
} else
|
||||
i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
|
||||
? 0755 : 0644;
|
||||
i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
|
||||
|
||||
if (!isempty(age) && !streq(age, "-")) {
|
||||
const char *a = age;
|
||||
@@ -2186,7 +2213,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
|
||||
continue;
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(j, items, iter) {
|
||||
if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME)
|
||||
if (!IN_SET(j->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA))
|
||||
continue;
|
||||
|
||||
if (path_equal(j->path, i->path)) {
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
|
||||
# See tmpfiles.d(5) for details
|
||||
|
||||
v /home 0755 - - -
|
||||
v /srv 0755 - - -
|
||||
Q /home 0755 - - -
|
||||
q /srv 0755 - - -
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
# See tmpfiles.d(5) for details
|
||||
|
||||
v /var/lib/machines 0700 - - -
|
||||
Q /var/lib/machines 0700 - - -
|
||||
|
||||
# Remove old temporary snapshots, but only at boot. Ideally we'd have
|
||||
# "self-destroying" btrfs snapshots that go away if the last last
|
||||
|
||||
+2
-2
@@ -8,8 +8,8 @@
|
||||
# See tmpfiles.d(5) for details
|
||||
|
||||
# Clear tmp directories separately, to make them easier to override
|
||||
v /tmp 1777 root root 10d
|
||||
v /var/tmp 1777 root root 30d
|
||||
q /tmp 1777 root root 10d
|
||||
q /var/tmp 1777 root root 30d
|
||||
|
||||
# Exclude namespace mountpoints created with PrivateTmp=yes
|
||||
x /tmp/systemd-private-%b-*
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
# See tmpfiles.d(5) for details
|
||||
|
||||
v /var 0755 - - -
|
||||
q /var 0755 - - -
|
||||
|
||||
L /var/run - - - - ../run
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ DeviceAllow=char-pts rw
|
||||
# implement the --image= option. Add these here, too.
|
||||
DeviceAllow=/dev/loop-control rw
|
||||
DeviceAllow=block-loop rw
|
||||
DeviceAllow=block-blkext rw
|
||||
|
||||
[Install]
|
||||
WantedBy=machines.target
|
||||
|
||||
Reference in New Issue
Block a user