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"?>
|
||||
<!--*-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>
|
||||
|
||||
|
@ -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)) {
|
||||
|
Loading…
Reference in New Issue
Block a user