From f17a8d6178c31281658956ec9c19b329bf421aa4 Mon Sep 17 00:00:00 2001 From: Franck Bui Date: Mon, 6 Aug 2018 12:29:54 +0200 Subject: [PATCH] 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. --- man/tmpfiles.d.xml | 91 ++++++++++++++++------------------------- src/tmpfiles/tmpfiles.c | 21 ++++++---- 2 files changed, 48 insertions(+), 64 deletions(-) diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index 968b481449..9f3660bd46 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -185,68 +185,47 @@ L /tmp/foobar - - - - /dev/null q - Similar to v. 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 d. 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 Q below. See btrfs-qgroup8 - for details about the btrfs quota group - concept. + Similar to v. 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 d. + + 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 Q below. See btrfs-qgroup8 for + details about the btrfs quota group concept. Q - Similar to q. 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. + Similar to q. 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. - Effectively, this has a similar effect as - q, 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 q and - Q, a concept of "subtree quotas" is - implemented. Each subvolume for which Q - 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 q 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. + Effectively, this has a similar effect as q, 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 + q and Q, a concept of "subtree quotas" is implemented. Each subvolume + for which Q 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 q 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. - It is recommended to use - Q 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 Q are typically - /home or - /var/lib/machines. In contrast, - q 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 q - are typically /var or - /var/tmp. As with Q, - q has no effect on the quota group - hierarchy if the subvolume exists and already has at least - one higher-level quota group assigned. + It is recommended to use Q 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 + Q are typically /home or /var/lib/machines. In + contrast, q 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 q are typically /var or + /var/tmp. + + As with q, Q 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. diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index cfd9044c5b..69c611e6c4 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -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);