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> <varlistentry>
<term><varname>q</varname></term> <term><varname>q</varname></term>
<listitem><para>Similar to <varname>v</varname>. However, <listitem><para>Similar to <varname>v</varname>. However, makes sure that the subvolume will be assigned to
makes sure that the subvolume will be assigned to the same the same higher-level quota groups as the subvolume it has been created in. This ensures that higher-level
higher-level quota groups as the subvolume it has been limits and accounting applied to the parent subvolume also include the specified subvolume. On non-btrfs file
created in. This ensures that higher-level limits and systems, this line type is identical to <varname>d</varname>.</para>
accounting applied to the parent subvolume also include the
specified subvolume. On non-btrfs file systems, this line <para>If the subvolume already exists, no change to the quota hierarchy is made, regardless of whether the
type is identical to <varname>d</varname>. If the subvolume subvolume is already attached to a quota group or not. Also see <varname>Q</varname> below. See <citerefentry
already exists and is already assigned to one or more higher project='die-net'><refentrytitle>btrfs-qgroup</refentrytitle><manvolnum>8</manvolnum></citerefentry> for
level quota groups, no change to the quota hierarchy is details about the btrfs quota group concept.</para></listitem>
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>
<varlistentry> <varlistentry>
<term><varname>Q</varname></term> <term><varname>Q</varname></term>
<listitem><para>Similar to <varname>q</varname>. However, <listitem><para>Similar to <varname>q</varname>. However, instead of copying the higher-level quota group
instead of copying the higher-level quota group assignments assignments from the parent as-is, the lowest quota group of the parent subvolume is determined that is not
from the parent as-is, the lowest quota group of the parent the leaf quota group. Then, an "intermediary" quota group is inserted that is one level below this level, and
subvolume is determined that is not the leaf quota shares the same ID part as the specified subvolume. If no higher-level quota group exists for the parent
group. Then, an "intermediary" quota group is inserted that subvolume, a new quota group at level 255 sharing the same ID as the specified subvolume is inserted
is one level below this level, and shares the same ID part instead. This new intermediary quota group is then assigned to the parent subvolume's higher-level quota
as the specified subvolume. If no higher-level quota group groups, and the specified subvolume's leaf quota group is assigned to it.</para>
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 <para>Effectively, this has a similar effect as <varname>q</varname>, however introduces a new higher-level
<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
quota group for the specified subvolume that may be used to subvolume and children subvolume created within it. Thus, by creating subvolumes only via
enforce limits and accounting to the specified subvolume and <varname>q</varname> and <varname>Q</varname>, a concept of "subtree quotas" is implemented. Each subvolume
children subvolume created within it. Thus, by creating for which <varname>Q</varname> is set will get a "subtree" quota group created, and all child subvolumes
subvolumes only via <varname>q</varname> and created within it will be assigned to it. Each subvolume for which <varname>q</varname> is set will not get
<varname>Q</varname>, a concept of "subtree quotas" is such a "subtree" quota group, but it is ensured that they are added to the same "subtree" quota group as
implemented. Each subvolume for which <varname>Q</varname> their immediate parents.</para>
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 <para>It is recommended to use <varname>Q</varname> for subvolumes that typically contain further subvolumes,
<varname>Q</varname> for subvolumes that typically contain and where it is desirable to have accounting and quota limits on all child subvolumes together. Examples for
further subvolumes, and where it is desirable to have <varname>Q</varname> are typically <filename>/home</filename> or <filename>/var/lib/machines</filename>. In
accounting and quota limits on all child subvolumes contrast, <varname>q</varname> should be used for subvolumes that either usually do not include further
together. Examples for <varname>Q</varname> are typically subvolumes or where no accounting and quota limits are needed that apply to all child subvolumes
<filename>/home</filename> or together. Examples for <varname>q</varname> are typically <filename>/var</filename> or
<filename>/var/lib/machines</filename>. In contrast, <filename>/var/tmp</filename>. </para>
<varname>q</varname> should be used for subvolumes that
either usually do not include further subvolumes or where no <para>As with <varname>q</varname>, <varname>Q</varname> has no effect on the quota group hierarchy if the
accounting and quota limits are needed that apply to all subvolume already exists, regardless of whether the subvolume already belong to a quota group or
child subvolumes together. Examples for <varname>q</varname> not.</para></listitem>
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>
<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); 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; _cleanup_close_ int pfd = -1;
CreationMode creation; CreationMode c;
int r; int r;
assert(path); assert(path);
if (!creation)
creation = &c;
pfd = path_open_parent_safe(path); pfd = path_open_parent_safe(path);
if (pfd < 0) if (pfd < 0)
return pfd; return pfd;
@ -1577,11 +1580,11 @@ static int create_directory_or_subvolume(const char *path, mode_t mode, bool sub
return -EEXIST; return -EEXIST;
} }
creation = CREATION_EXISTING; *creation = CREATION_EXISTING;
} else } 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); r = openat(pfd, basename(path), O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (r < 0) if (r < 0)
@ -1595,7 +1598,7 @@ static int create_directory(Item *i, const char *path) {
assert(i); assert(i);
assert(IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY)); 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) if (fd == -EEXIST)
return 0; return 0;
if (fd < 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) { static int create_subvolume(Item *i, const char *path) {
_cleanup_close_ int fd = -1; _cleanup_close_ int fd = -1;
CreationMode creation;
int r, q = 0; int r, q = 0;
assert(i); assert(i);
assert(IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)); 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) if (fd == -EEXIST)
return 0; return 0;
if (fd < 0) if (fd < 0)
return fd; 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); r = btrfs_subvol_auto_qgroup_fd(fd, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
if (r == -ENOTTY) if (r == -ENOTTY)
log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path); log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path);