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:
parent
b2776a60f3
commit
f17a8d6178
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue