tmpfiles: don't adjust qgroups on existing subvolumes

The qgroup logic (types 'q' and 'Q') only has an effect if there's no previous
setup at all, and any explicitly configured subvolumes with their qgroups are
left entirely unmodified.

The idea is that if users want a different logic than the one we set up by
default, then by all means they should do that before hand, and tmpfiles won't
override their logic.
This commit is contained in:
Franck Bui 2018-08-06 12:29:54 +02:00 committed by Lennart Poettering
parent b2776a60f3
commit f17a8d6178
2 changed files with 48 additions and 64 deletions

View File

@ -185,68 +185,47 @@ L /tmp/foobar - - - - /dev/null</programlisting>
<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>
<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>.</para>
<para>If the subvolume already exists, no change to the quota hierarchy is made, regardless of whether the
subvolume is already attached to a quota group or not. 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>
<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>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>
<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>. </para>
<para>As with <varname>q</varname>, <varname>Q</varname> has no effect on the quota group hierarchy if the
subvolume already exists, regardless of whether the subvolume already belong to a quota group or
not.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -1525,13 +1525,16 @@ static const char *creation_mode_verb_table[_CREATION_MODE_MAX] = {
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(creation_mode_verb, CreationMode);
static int create_directory_or_subvolume(const char *path, mode_t mode, bool subvol) {
static int create_directory_or_subvolume(const char *path, mode_t mode, bool subvol, CreationMode *creation) {
_cleanup_close_ int pfd = -1;
CreationMode creation;
CreationMode c;
int r;
assert(path);
if (!creation)
creation = &c;
pfd = path_open_parent_safe(path);
if (pfd < 0)
return pfd;
@ -1577,11 +1580,11 @@ static int create_directory_or_subvolume(const char *path, mode_t mode, bool sub
return -EEXIST;
}
creation = CREATION_EXISTING;
*creation = CREATION_EXISTING;
} else
creation = CREATION_NORMAL;
*creation = CREATION_NORMAL;
log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), path);
log_debug("%s directory \"%s\".", creation_mode_verb_to_string(*creation), path);
r = openat(pfd, basename(path), O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (r < 0)
@ -1595,7 +1598,7 @@ static int create_directory(Item *i, const char *path) {
assert(i);
assert(IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY));
fd = create_directory_or_subvolume(path, i->mode, false);
fd = create_directory_or_subvolume(path, i->mode, false, NULL);
if (fd == -EEXIST)
return 0;
if (fd < 0)
@ -1606,18 +1609,20 @@ static int create_directory(Item *i, const char *path) {
static int create_subvolume(Item *i, const char *path) {
_cleanup_close_ int fd = -1;
CreationMode creation;
int r, q = 0;
assert(i);
assert(IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA));
fd = create_directory_or_subvolume(path, i->mode, true);
fd = create_directory_or_subvolume(path, i->mode, true, &creation);
if (fd == -EEXIST)
return 0;
if (fd < 0)
return fd;
if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
if (creation == CREATION_NORMAL &&
IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
r = btrfs_subvol_auto_qgroup_fd(fd, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
if (r == -ENOTTY)
log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path);