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);