mirror of
https://github.com/systemd/systemd.git
synced 2024-11-24 10:43:35 +08:00
tmpfiles: introduce "q" and "Q" for creating quota-enabled btrfs subvolumes
This allows us to set up the quota group hierarchy in a reasonable way on btrfs file systems.
This commit is contained in:
parent
8c9cfc2844
commit
5fb13eb51b
@ -1,5 +1,4 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
|
||||||
<!--*-nxml-*-->
|
|
||||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
<!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.
|
This file is part of systemd.
|
||||||
@ -172,7 +171,77 @@
|
|||||||
<listitem><para>Create a subvolume if the path does not
|
<listitem><para>Create a subvolume if the path does not
|
||||||
exist yet and the file system supports this
|
exist yet and the file system supports this
|
||||||
(btrfs). Otherwise create a normal directory, in the same
|
(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>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
@ -504,13 +573,12 @@
|
|||||||
<para>When the age is set to zero, the files are cleaned
|
<para>When the age is set to zero, the files are cleaned
|
||||||
unconditionally.</para>
|
unconditionally.</para>
|
||||||
|
|
||||||
<para>The age field only applies to lines
|
<para>The age field only applies to lines starting with
|
||||||
starting with <varname>d</varname>,
|
<varname>d</varname>, <varname>D</varname>,
|
||||||
<varname>D</varname>, <varname>v</varname>,
|
<varname>v</varname>, <varname>q</varname>,
|
||||||
<varname>C</varname>, <varname>x</varname> and
|
<varname>Q</varname>, <varname>C</varname>, <varname>x</varname>
|
||||||
<varname>X</varname>. If omitted or set to
|
and <varname>X</varname>. If omitted or set to
|
||||||
<literal>-</literal>, no automatic clean-up is
|
<literal>-</literal>, no automatic clean-up is done.</para>
|
||||||
done.</para>
|
|
||||||
|
|
||||||
<para>If the age field starts with a tilde character
|
<para>If the age field starts with a tilde character
|
||||||
<literal>~</literal>, the clean-up is only applied to files and
|
<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>setfattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||||
<citerefentry project='man-pages'><refentrytitle>setfacl</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>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>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -69,6 +69,8 @@ typedef enum ItemType {
|
|||||||
CREATE_DIRECTORY = 'd',
|
CREATE_DIRECTORY = 'd',
|
||||||
TRUNCATE_DIRECTORY = 'D',
|
TRUNCATE_DIRECTORY = 'D',
|
||||||
CREATE_SUBVOLUME = 'v',
|
CREATE_SUBVOLUME = 'v',
|
||||||
|
CREATE_SUBVOLUME_INHERIT_QUOTA = 'q',
|
||||||
|
CREATE_SUBVOLUME_NEW_QUOTA = 'Q',
|
||||||
CREATE_FIFO = 'p',
|
CREATE_FIFO = 'p',
|
||||||
CREATE_SYMLINK = 'L',
|
CREATE_SYMLINK = 'L',
|
||||||
CREATE_CHAR_DEVICE = 'c',
|
CREATE_CHAR_DEVICE = 'c',
|
||||||
@ -180,6 +182,8 @@ static bool takes_ownership(ItemType t) {
|
|||||||
CREATE_DIRECTORY,
|
CREATE_DIRECTORY,
|
||||||
TRUNCATE_DIRECTORY,
|
TRUNCATE_DIRECTORY,
|
||||||
CREATE_SUBVOLUME,
|
CREATE_SUBVOLUME,
|
||||||
|
CREATE_SUBVOLUME_INHERIT_QUOTA,
|
||||||
|
CREATE_SUBVOLUME_NEW_QUOTA,
|
||||||
CREATE_FIFO,
|
CREATE_FIFO,
|
||||||
CREATE_SYMLINK,
|
CREATE_SYMLINK,
|
||||||
CREATE_CHAR_DEVICE,
|
CREATE_CHAR_DEVICE,
|
||||||
@ -1198,16 +1202,16 @@ static int create_item(Item *i) {
|
|||||||
case CREATE_DIRECTORY:
|
case CREATE_DIRECTORY:
|
||||||
case TRUNCATE_DIRECTORY:
|
case TRUNCATE_DIRECTORY:
|
||||||
case CREATE_SUBVOLUME:
|
case CREATE_SUBVOLUME:
|
||||||
|
case CREATE_SUBVOLUME_INHERIT_QUOTA:
|
||||||
|
case CREATE_SUBVOLUME_NEW_QUOTA:
|
||||||
|
|
||||||
RUN_WITH_UMASK(0000)
|
RUN_WITH_UMASK(0000)
|
||||||
mkdir_parents_label(i->path, 0755);
|
mkdir_parents_label(i->path, 0755);
|
||||||
|
|
||||||
if (i->type == CREATE_SUBVOLUME)
|
if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) {
|
||||||
RUN_WITH_UMASK((~i->mode) & 0777) {
|
RUN_WITH_UMASK((~i->mode) & 0777)
|
||||||
r = btrfs_subvol_make(i->path);
|
r = btrfs_subvol_make(i->path);
|
||||||
log_debug_errno(r, "Creating subvolume \"%s\": %m", i->path);
|
} else
|
||||||
}
|
|
||||||
else
|
|
||||||
r = 0;
|
r = 0;
|
||||||
|
|
||||||
if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY)
|
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);
|
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);
|
r = path_set_perms(i, i->path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1492,6 +1514,8 @@ static int remove_item(Item *i) {
|
|||||||
case TRUNCATE_FILE:
|
case TRUNCATE_FILE:
|
||||||
case CREATE_DIRECTORY:
|
case CREATE_DIRECTORY:
|
||||||
case CREATE_SUBVOLUME:
|
case CREATE_SUBVOLUME:
|
||||||
|
case CREATE_SUBVOLUME_INHERIT_QUOTA:
|
||||||
|
case CREATE_SUBVOLUME_NEW_QUOTA:
|
||||||
case CREATE_FIFO:
|
case CREATE_FIFO:
|
||||||
case CREATE_SYMLINK:
|
case CREATE_SYMLINK:
|
||||||
case CREATE_CHAR_DEVICE:
|
case CREATE_CHAR_DEVICE:
|
||||||
@ -1583,6 +1607,8 @@ static int clean_item(Item *i) {
|
|||||||
switch (i->type) {
|
switch (i->type) {
|
||||||
case CREATE_DIRECTORY:
|
case CREATE_DIRECTORY:
|
||||||
case CREATE_SUBVOLUME:
|
case CREATE_SUBVOLUME:
|
||||||
|
case CREATE_SUBVOLUME_INHERIT_QUOTA:
|
||||||
|
case CREATE_SUBVOLUME_NEW_QUOTA:
|
||||||
case TRUNCATE_DIRECTORY:
|
case TRUNCATE_DIRECTORY:
|
||||||
case IGNORE_PATH:
|
case IGNORE_PATH:
|
||||||
case COPY_FILES:
|
case COPY_FILES:
|
||||||
@ -1819,6 +1845,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
|||||||
|
|
||||||
case CREATE_DIRECTORY:
|
case CREATE_DIRECTORY:
|
||||||
case CREATE_SUBVOLUME:
|
case CREATE_SUBVOLUME:
|
||||||
|
case CREATE_SUBVOLUME_INHERIT_QUOTA:
|
||||||
|
case CREATE_SUBVOLUME_NEW_QUOTA:
|
||||||
case TRUNCATE_DIRECTORY:
|
case TRUNCATE_DIRECTORY:
|
||||||
case CREATE_FIFO:
|
case CREATE_FIFO:
|
||||||
case IGNORE_PATH:
|
case IGNORE_PATH:
|
||||||
@ -1983,8 +2011,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
|||||||
i.mode = m;
|
i.mode = m;
|
||||||
i.mode_set = true;
|
i.mode_set = true;
|
||||||
} else
|
} else
|
||||||
i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY)
|
i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
|
||||||
? 0755 : 0644;
|
|
||||||
|
|
||||||
if (!isempty(age) && !streq(age, "-")) {
|
if (!isempty(age) && !streq(age, "-")) {
|
||||||
const char *a = age;
|
const char *a = age;
|
||||||
@ -2186,7 +2213,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
ORDERED_HASHMAP_FOREACH(j, items, iter) {
|
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;
|
continue;
|
||||||
|
|
||||||
if (path_equal(j->path, i->path)) {
|
if (path_equal(j->path, i->path)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user