Merge pull request #1641 from poettering/btrfs-quota

btrfs quota beef up and various other unrelated changes
This commit is contained in:
Daniel Mack
2015-10-23 10:50:53 +02:00
35 changed files with 1319 additions and 201 deletions
+852 -53
View File
File diff suppressed because it is too large Load Diff
+57 -20
View File
@@ -47,25 +47,17 @@ typedef enum BtrfsSnapshotFlags {
BTRFS_SNAPSHOT_FALLBACK_COPY = 1,
BTRFS_SNAPSHOT_READ_ONLY = 2,
BTRFS_SNAPSHOT_RECURSIVE = 4,
BTRFS_SNAPSHOT_QUOTA = 8,
} BtrfsSnapshotFlags;
typedef enum BtrfsRemoveFlags {
BTRFS_REMOVE_RECURSIVE = 1,
BTRFS_REMOVE_QUOTA = 2,
} BtrfsRemoveFlags;
int btrfs_is_filesystem(int fd);
int btrfs_is_subvol(int fd);
int btrfs_subvol_make(const char *path);
int btrfs_subvol_make_label(const char *path);
int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags);
int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags);
int btrfs_subvol_set_read_only_fd(int fd, bool b);
int btrfs_subvol_set_read_only(const char *path, bool b);
int btrfs_subvol_get_read_only_fd(int fd);
int btrfs_subvol_get_id(int fd, const char *subvolume, uint64_t *ret);
int btrfs_subvol_get_id_fd(int fd, uint64_t *ret);
int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *info);
int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *quota);
int btrfs_reflink(int infd, int outfd);
int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz);
@@ -78,14 +70,59 @@ int btrfs_defrag(const char *p);
int btrfs_quota_enable_fd(int fd, bool b);
int btrfs_quota_enable(const char *path, bool b);
int btrfs_quota_limit_fd(int fd, uint64_t referenced_max);
int btrfs_quota_limit(const char *path, uint64_t referenced_max);
int btrfs_quota_scan_start(int fd);
int btrfs_quota_scan_wait(int fd);
int btrfs_quota_scan_ongoing(int fd);
int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only);
int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only);
int btrfs_subvol_remove(const char *path, bool recursive);
int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive);
int btrfs_subvol_make(const char *path);
int btrfs_subvol_make_label(const char *path);
int btrfs_qgroup_create(int fd, uint64_t level, uint64_t id);
int btrfs_qgroup_destroy(int fd, uint64_t level, uint64_t id);
int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags);
int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags);
int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags);
int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags);
int btrfs_subvol_set_read_only_fd(int fd, bool b);
int btrfs_subvol_set_read_only(const char *path, bool b);
int btrfs_subvol_get_read_only_fd(int fd);
int btrfs_subvol_get_id(int fd, const char *subvolume, uint64_t *ret);
int btrfs_subvol_get_id_fd(int fd, uint64_t *ret);
int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret);
int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *info);
int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret);
int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *quota);
int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *quota);
int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max);
int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max);
int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool new_qgroup);
int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup);
int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret);
int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id);
int btrfs_qgroup_create(int fd, uint64_t qgroupid);
int btrfs_qgroup_destroy(int fd, uint64_t qgroupid);
int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid);
int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max);
int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max);
int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid);
int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent);
int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent);
int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret);
int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *quota);
int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *quota);
+4
View File
@@ -494,6 +494,10 @@ struct btrfs_ioctl_quota_ctl_args {
#define BTRFS_QGROUP_LIMIT_KEY 244
#endif
#ifndef BTRFS_QGROUP_RELATION_KEY
#define BTRFS_QGROUP_RELATION_KEY 246
#endif
#ifndef BTRFS_ROOT_BACKREF_KEY
#define BTRFS_ROOT_BACKREF_KEY 144
#endif
+18 -5
View File
@@ -796,14 +796,11 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd
return changed;
}
int fsck_exists(const char *fstype) {
static int binary_is_good(const char *binary) {
_cleanup_free_ char *p = NULL, *d = NULL;
const char *checker;
int r;
checker = strjoina("fsck.", fstype);
r = find_binary(checker, true, &p);
r = find_binary(binary, true, &p);
if (r < 0)
return r;
@@ -820,6 +817,22 @@ int fsck_exists(const char *fstype) {
return 0;
}
int fsck_exists(const char *fstype) {
const char *checker;
checker = strjoina("fsck.", fstype);
return binary_is_good(checker);
}
int mkfs_exists(const char *fstype) {
const char *mkfs;
mkfs = strjoina("mkfs.", fstype);
return binary_is_good(mkfs);
}
char *prefix_root(const char *root, const char *path) {
char *n, *p;
size_t l;
+1
View File
@@ -63,6 +63,7 @@ int find_binary(const char *name, bool local, char **filename);
bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
int fsck_exists(const char *fstype);
int mkfs_exists(const char *fstype);
/* Iterates through the path prefixes of the specified path, going up
* the tree, to root. Also returns "" (and not "/"!) for the root
+2 -2
View File
@@ -120,7 +120,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
/* This could be a subvolume, try to remove it */
r = btrfs_subvol_remove_fd(fd, de->d_name, true);
r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r < 0) {
if (r != -ENOTTY && r != -EINVAL) {
if (ret == 0)
@@ -178,7 +178,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
if ((flags & (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) == (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) {
/* Try to remove as subvolume first */
r = btrfs_subvol_remove(path, true);
r = btrfs_subvol_remove(path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r >= 0)
return r;
+4 -13
View File
@@ -2381,25 +2381,16 @@ bool is_device_path(const char *path) {
int dir_is_empty(const char *path) {
_cleanup_closedir_ DIR *d;
struct dirent *de;
d = opendir(path);
if (!d)
return -errno;
for (;;) {
struct dirent *de;
FOREACH_DIRENT(de, d, return -errno)
return 0;
errno = 0;
de = readdir(d);
if (!de && errno != 0)
return -errno;
if (!de)
return 1;
if (!hidden_file(de->d_name))
return 0;
}
return 1;
}
char* dirname_malloc(const char *path) {
+8
View File
@@ -358,6 +358,14 @@ bool is_device_path(const char *path);
int dir_is_empty(const char *path);
char* dirname_malloc(const char *path);
static inline int dir_is_populated(const char *path) {
int r;
r = dir_is_empty(path);
if (r < 0)
return r;
return !r;
}
char* lookup_uid(uid_t uid);
char* getlogname_malloc(void);
char* getusername_malloc(void);
+4 -5
View File
@@ -1173,7 +1173,6 @@ int bus_exec_context_set_transient_property(
unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
}
}
return 1;
@@ -1262,6 +1261,10 @@ int bus_exec_context_set_transient_property(
if (r < 0)
return r;
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
r = fflush_and_check(f);
if (r < 0)
return r;
@@ -1279,10 +1282,6 @@ int bus_exec_context_set_transient_property(
}
}
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
return 1;
} else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
+2 -2
View File
@@ -78,7 +78,7 @@ TarExport *tar_export_unref(TarExport *e) {
}
if (e->temp_path) {
(void) btrfs_subvol_remove(e->temp_path, false);
(void) btrfs_subvol_remove(e->temp_path, BTRFS_REMOVE_QUOTA);
free(e->temp_path);
}
@@ -283,7 +283,7 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType
if (e->st.st_ino == 256) { /* might be a btrfs subvolume? */
BtrfsQuotaInfo q;
r = btrfs_subvol_get_quota_fd(sfd, &q);
r = btrfs_subvol_get_subtree_quota_fd(sfd, 0, &q);
if (r >= 0)
e->quota_referenced = q.referenced;
+2
View File
@@ -235,6 +235,8 @@ static int tar_import_fork_tar(TarImport *i) {
return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
} else if (r < 0)
return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
else
(void) import_assign_pool_quota_and_warn(i->temp_path);
i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
if (i->tar_fd < 0)
+3 -2
View File
@@ -138,7 +138,7 @@ int pull_make_local_copy(const char *final, const char *image_root, const char *
if (force_local)
(void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
r = btrfs_subvol_snapshot(final, p, 0);
r = btrfs_subvol_snapshot(final, p, BTRFS_SNAPSHOT_QUOTA);
if (r == -ENOTTY) {
r = copy_tree(final, p, false);
if (r < 0)
@@ -366,9 +366,10 @@ int pull_verify(PullJob *main_job,
log_info("SHA256 checksum of %s is valid.", main_job->url);
assert(!settings_job || settings_job->state == PULL_JOB_DONE);
assert(!settings_job || IN_SET(settings_job->state, PULL_JOB_DONE, PULL_JOB_FAILED));
if (settings_job &&
settings_job->state == PULL_JOB_DONE &&
settings_job->error == 0 &&
!settings_job->etag_exists) {
+12 -4
View File
@@ -490,10 +490,16 @@ static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) {
return r;
if (version == DKR_PULL_V2) {
char **k = NULL;
char **k;
STRV_FOREACH(k, i->ancestry) {
_cleanup_free_ char *d = strjoin(i->image_root, "/.dkr-", *k, NULL);
r = btrfs_subvol_remove(d, false);
_cleanup_free_ char *d;
d = strjoin(i->image_root, "/.dkr-", *k, NULL);
if (!d)
return -ENOMEM;
r = btrfs_subvol_remove(d, BTRFS_REMOVE_QUOTA);
if (r < 0)
return r;
}
@@ -531,12 +537,14 @@ static int dkr_pull_job_on_open_disk(PullJob *j) {
const char *base_path;
base_path = strjoina(i->image_root, "/.dkr-", base);
r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY);
r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY|BTRFS_SNAPSHOT_QUOTA);
} else
r = btrfs_subvol_make(i->temp_path);
if (r < 0)
return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path);
(void) import_assign_pool_quota_and_warn(i->temp_path);
j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
if (j->disk_fd < 0)
return j->disk_fd;
+3 -3
View File
@@ -349,9 +349,9 @@ static int raw_pull_make_local_copy(RawPull *i) {
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
else if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings);
log_info("Create new settings file '%s.nspawn'", i->local);
log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
else
log_info("Created new settings file '%s.nspawn'", i->local);
}
return 0;
+5 -3
View File
@@ -247,9 +247,9 @@ static int tar_pull_make_local_copy(TarPull *i) {
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
else if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings);
log_info("Create new settings file '%s.nspawn'", i->local);
log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings);
else
log_info("Created new settings file '%s.nspawn'", i->local);
}
return 0;
@@ -410,6 +410,8 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) {
return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path);
} else if (r < 0)
return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path);
else
(void) import_assign_pool_quota_and_warn(i->temp_path);
j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid);
if (j->disk_fd < 0)
+10 -6
View File
@@ -1049,9 +1049,13 @@ error:
}
void session_restore_vt(Session *s) {
static const struct vt_mode mode = {
.mode = VT_AUTO,
};
_cleanup_free_ char *utf8 = NULL;
int vt, kb = K_XLATE;
struct vt_mode mode = { 0 };
int vt, kb, old_fd;
/* We need to get a fresh handle to the virtual terminal,
* since the old file-descriptor is potentially in a hung-up
@@ -1059,7 +1063,7 @@ void session_restore_vt(Session *s) {
* little dance to avoid having the terminal be available
* for reuse before we've cleaned it up.
*/
int old_fd = s->vtfd;
old_fd = s->vtfd;
s->vtfd = -1;
vt = session_open_vt(s);
@@ -1072,13 +1076,13 @@ void session_restore_vt(Session *s) {
if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1')
kb = K_UNICODE;
else
kb = K_XLATE;
(void) ioctl(vt, KDSKBMODE, kb);
mode.mode = VT_AUTO;
(void) ioctl(vt, VT_SETMODE, &mode);
fchown(vt, 0, -1);
(void) fchown(vt, 0, (gid_t) -1);
s->vtfd = safe_close(s->vtfd);
}
+1 -1
View File
@@ -2382,7 +2382,7 @@ static int set_limit(int argc, char *argv[], void *userdata) {
uint64_t limit;
int r;
if (streq(argv[argc-1], "-"))
if (STR_IN_SET(argv[argc-1], "-", "none", "infinity"))
limit = (uint64_t) -1;
else {
r = parse_size(argv[argc-1], 1024, &limit);
+5 -3
View File
@@ -79,7 +79,7 @@ static int property_get_pool_usage(
if (fd >= 0) {
BtrfsQuotaInfo q;
if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
usage = q.referenced;
}
@@ -115,7 +115,7 @@ static int property_get_pool_limit(
if (fd >= 0) {
BtrfsQuotaInfo q;
if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
size = q.referenced_max;
}
@@ -831,7 +831,9 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus
if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
r = btrfs_quota_limit("/var/lib/machines", limit);
(void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit);
r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit);
if (r == -ENOTTY)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
if (r < 0)
+20
View File
@@ -85,6 +85,26 @@ Settings* settings_free(Settings *s) {
return NULL;
}
bool settings_private_network(Settings *s) {
assert(s);
return
s->private_network > 0 ||
s->network_veth > 0 ||
s->network_bridge ||
s->network_interfaces ||
s->network_macvlan ||
s->network_ipvlan;
}
bool settings_network_veth(Settings *s) {
assert(s);
return
s->network_veth > 0 ||
s->network_bridge;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode");
int config_parse_expose_port(
+3
View File
@@ -75,6 +75,9 @@ typedef struct Settings {
int settings_load(FILE *f, const char *path, Settings **ret);
Settings* settings_free(Settings *s);
bool settings_network_veth(Settings *s);
bool settings_private_network(Settings *s);
DEFINE_TRIVIAL_CLEANUP_FUNC(Settings*, settings_free);
const struct ConfigPerfItem* nspawn_gperf_lookup(const char *key, unsigned length);
+19 -15
View File
@@ -2912,11 +2912,17 @@ static int load_settings(void) {
}
if ((arg_settings_mask & SETTING_CAPABILITY) == 0) {
uint64_t plus;
if (!arg_settings_trusted && settings->capability != 0)
log_warning("Ignoring Capability= setting, file %s is not trusted.", p);
else
arg_retain |= settings->capability;
plus = settings->capability;
if (settings_private_network(settings))
plus |= (1ULL << CAP_NET_ADMIN);
if (!arg_settings_trusted && plus != 0) {
if (settings->capability != 0)
log_warning("Ignoring Capability= setting, file %s is not trusted.", p);
} else
arg_retain |= plus;
arg_retain &= ~settings->drop_capability;
}
@@ -2972,6 +2978,9 @@ static int load_settings(void) {
if (!arg_settings_trusted)
log_warning("Ignoring network settings, file %s is not trusted.", p);
else {
arg_network_veth = settings_private_network(settings);
arg_private_network = settings_private_network(settings);
strv_free(arg_network_interfaces);
arg_network_interfaces = settings->network_interfaces;
settings->network_interfaces = NULL;
@@ -2987,10 +2996,6 @@ static int load_settings(void) {
free(arg_network_bridge);
arg_network_bridge = settings->network_bridge;
settings->network_bridge = NULL;
arg_network_veth = settings->network_veth > 0 || settings->network_bridge;
arg_private_network = true; /* all these settings imply private networking */
}
}
@@ -3096,7 +3101,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
if (r < 0) {
log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory);
goto finish;
@@ -3120,7 +3125,7 @@ int main(int argc, char *argv[]) {
}
if (arg_template) {
r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
if (r == -EEXIST) {
if (!arg_quiet)
log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template);
@@ -3143,10 +3148,9 @@ int main(int argc, char *argv[]) {
} else {
const char *p;
p = strjoina(arg_directory,
argc > optind && path_is_absolute(argv[optind]) ? argv[optind] : "/usr/bin/");
if (access(p, F_OK) < 0) {
log_error("Directory %s lacks the binary to execute or doesn't look like a binary tree. Refusing.", arg_directory);
p = strjoina(arg_directory, "/usr/");
if (laccess(p, F_OK) < 0) {
log_error("Directory %s doesn't look like it has an OS tree. Refusing.", arg_directory);
r = -EINVAL;
goto finish;
}
@@ -3591,7 +3595,7 @@ finish:
if (remove_subvol && arg_directory) {
int k;
k = btrfs_subvol_remove(arg_directory, true);
k = btrfs_subvol_remove(arg_directory, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (k < 0)
log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory);
}
+27
View File
@@ -19,6 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "btrfs-util.h"
#include "util.h"
#include "import-util.h"
@@ -201,3 +202,29 @@ bool dkr_id_is_valid(const char *id) {
return true;
}
int import_assign_pool_quota_and_warn(const char *path) {
int r;
r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true);
if (r == -ENOTTY) {
log_debug_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, as directory is not on btrfs or not a subvolume. Ignoring.");
return 0;
}
if (r < 0)
return log_error_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines: %m");
if (r > 0)
log_info("Set up default quota hierarchy for /var/lib/machines.");
r = btrfs_subvol_auto_qgroup(path, 0, true);
if (r == -ENOTTY) {
log_debug_errno(r, "Failed to set up quota hierarchy for %s, as directory is not on btrfs or not a subvolume. Ignoring.", path);
return 0;
}
if (r < 0)
return log_error_errno(r, "Failed to set up default quota hierarchy for %s: %m", path);
if (r > 0)
log_info("Set up default quota hierarchy for %s.", path);
return 0;
}
+2
View File
@@ -47,3 +47,5 @@ bool dkr_id_is_valid(const char *id);
bool dkr_ref_is_valid(const char *ref);
bool dkr_digest_is_valid(const char *digest);
#define dkr_tag_is_valid(tag) filename_is_valid(tag)
int import_assign_pool_quota_and_warn(const char *path);
+30 -11
View File
@@ -176,11 +176,10 @@ static int image_make(
return r;
if (r) {
BtrfsSubvolInfo info;
BtrfsQuotaInfo quota;
/* It's a btrfs subvolume */
r = btrfs_subvol_get_info_fd(fd, &info);
r = btrfs_subvol_get_info_fd(fd, 0, &info);
if (r < 0)
return r;
@@ -195,13 +194,17 @@ static int image_make(
if (r < 0)
return r;
r = btrfs_subvol_get_quota_fd(fd, &quota);
if (r >= 0) {
(*ret)->usage = quota.referenced;
(*ret)->usage_exclusive = quota.exclusive;
if (btrfs_quota_scan_ongoing(fd) == 0) {
BtrfsQuotaInfo quota;
(*ret)->limit = quota.referenced_max;
(*ret)->limit_exclusive = quota.exclusive_max;
r = btrfs_subvol_get_subtree_quota_fd(fd, 0, &quota);
if (r >= 0) {
(*ret)->usage = quota.referenced;
(*ret)->usage_exclusive = quota.exclusive;
(*ret)->limit = quota.referenced_max;
(*ret)->limit_exclusive = quota.exclusive_max;
}
}
return 1;
@@ -397,7 +400,7 @@ int image_remove(Image *i) {
switch (i->type) {
case IMAGE_SUBVOLUME:
r = btrfs_subvol_remove(i->path, true);
r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
if (r < 0)
return r;
break;
@@ -587,7 +590,12 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
case IMAGE_DIRECTORY:
new_path = strjoina("/var/lib/machines/", new_name);
r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE);
r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
/* Enable "subtree" quotas for the copy, if we didn't
* copy any quota from the source. */
(void) btrfs_subvol_auto_qgroup(i->path, 0, true);
break;
case IMAGE_RAW:
@@ -629,6 +637,10 @@ int image_read_only(Image *i, bool b) {
switch (i->type) {
case IMAGE_SUBVOLUME:
/* Note that we set the flag only on the top-level
* subvolume of the image. */
r = btrfs_subvol_set_read_only(i->path, b);
if (r < 0)
return r;
@@ -729,7 +741,14 @@ int image_set_limit(Image *i, uint64_t referenced_max) {
if (i->type != IMAGE_SUBVOLUME)
return -EOPNOTSUPP;
return btrfs_quota_limit(i->path, referenced_max);
/* We set the quota both for the subvolume as well as for the
* subtree. The latter is mostly for historical reasons, since
* we didn't use to have a concept of subtree quota, and hence
* only modified the subvolume quota. */
(void) btrfs_qgroup_set_limit(i->path, 0, referenced_max);
(void) btrfs_subvol_auto_qgroup(i->path, 0, true);
return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max);
}
int image_name_lock(const char *name, int operation, LockFile *ret) {
+36 -9
View File
@@ -170,7 +170,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
};
_cleanup_close_ int fd = -1, control = -1, loop = -1;
_cleanup_free_ char* loopdev = NULL;
char tmpdir[] = "/tmp/import-mount.XXXXXX", *mntdir = NULL;
char tmpdir[] = "/tmp/machine-pool.XXXXXX", *mntdir = NULL;
bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false;
char buf[FORMAT_BYTES_MAX];
int r, nr = -1;
@@ -194,14 +194,35 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
r = btrfs_quota_enable("/var/lib/machines", true);
if (r < 0)
log_warning_errno(r, "Failed to enable quota, ignoring: %m");
log_warning_errno(r, "Failed to enable quota for /var/lib/machines, ignoring: %m");
r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true);
if (r < 0)
log_warning_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, ignoring: %m");
return 1;
}
if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0) {
log_debug("/var/lib/machines is already a mount point, not creating loopback file for it.");
return 0;
}
if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0 ||
dir_is_empty("/var/lib/machines") == 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "/var/lib/machines is not a btrfs file system. Operation is not supported on legacy file systems.");
r = dir_is_populated("/var/lib/machines");
if (r < 0 && r != -ENOENT)
return r;
if (r > 0) {
log_debug("/var/log/machines is already populated, not creating loopback file for it.");
return 0;
}
r = mkfs_exists("btrfs");
if (r == -ENOENT) {
log_debug("mkfs.btrfs is missing, cannot create loopback file for /var/lib/machines.");
return 0;
}
if (r < 0)
return r;
fd = setup_machine_raw(size, error);
if (fd < 0)
@@ -266,6 +287,10 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
if (r < 0)
log_warning_errno(r, "Failed to enable quota, ignoring: %m");
r = btrfs_subvol_auto_qgroup(mntdir, 0, true);
if (r < 0)
log_warning_errno(r, "Failed to set up default quota hierarchy, ignoring: %m");
if (chmod(mntdir, 0700) < 0) {
r = sd_bus_error_set_errnof(error, errno, "Failed to fix owner: %m");
goto fail;
@@ -286,7 +311,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
(void) rmdir(mntdir);
(void) rmdir(tmpdir);
return 0;
return 1;
fail:
if (mntdir_mounted)
@@ -370,9 +395,11 @@ int grow_machine_directory(void) {
if (r <= 0)
return r;
r = btrfs_quota_limit("/var/lib/machines", new_size);
if (r < 0)
return r;
/* Also bump the quota, of both the subvolume leaf qgroup, as
* well as of any subtree quota group by the same id but a
* higher level, if it exists. */
(void) btrfs_qgroup_set_limit("/var/lib/machines", 0, new_size);
(void) btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, new_size);
log_info("Grew /var/lib/machines btrfs loopback file system to %s.", format_bytes(buf, sizeof(buf), new_size));
return 1;
+6 -6
View File
@@ -7399,12 +7399,12 @@ static int talk_initctl(void) {
static int systemctl_main(int argc, char *argv[]) {
static const Verb verbs[] = {
{ "list-units", VERB_ANY, 1, VERB_DEFAULT, list_units },
{ "list-unit-files", VERB_ANY, 1, 0, list_unit_files },
{ "list-sockets", VERB_ANY, 1, 0, list_sockets },
{ "list-timers", VERB_ANY, 1, 0, list_timers },
{ "list-jobs", VERB_ANY, 1, 0, list_jobs },
{ "list-machines", VERB_ANY, 1, 0, list_machines },
{ "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_units },
{ "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
{ "list-sockets", VERB_ANY, VERB_ANY, 0, list_sockets },
{ "list-timers", VERB_ANY, VERB_ANY, 0, list_timers },
{ "list-jobs", VERB_ANY, VERB_ANY, 0, list_jobs },
{ "list-machines", VERB_ANY, VERB_ANY, 0, list_machines },
{ "clear-jobs", VERB_ANY, 1, 0, daemon_reload },
{ "cancel", 2, VERB_ANY, 0, cancel_job },
{ "start", 2, VERB_ANY, 0, start_unit },
+58 -10
View File
@@ -27,17 +27,17 @@
#include "btrfs-util.h"
int main(int argc, char *argv[]) {
BtrfsQuotaInfo quota;
int r, fd;
fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
if (fd < 0)
log_error_errno(errno, "Failed to open root directory: %m");
else {
BtrfsSubvolInfo info;
BtrfsQuotaInfo quota;
char ts[FORMAT_TIMESTAMP_MAX], bs[FORMAT_BYTES_MAX];
BtrfsSubvolInfo info;
r = btrfs_subvol_get_info_fd(fd, &info);
r = btrfs_subvol_get_info_fd(fd, 0, &info);
if (r < 0)
log_error_errno(r, "Failed to get subvolume info: %m");
else {
@@ -45,7 +45,7 @@ int main(int argc, char *argv[]) {
log_info("read-only (search): %s", yes_no(info.read_only));
}
r = btrfs_subvol_get_quota_fd(fd, &quota);
r = btrfs_qgroup_get_quota_fd(fd, 0, &quota);
if (r < 0)
log_error_errno(r, "Failed to get quota info: %m");
else {
@@ -80,15 +80,15 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
r = btrfs_subvol_remove("/xxxtest", false);
r = btrfs_subvol_remove("/xxxtest", BTRFS_REMOVE_QUOTA);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
r = btrfs_subvol_remove("/xxxtest2", false);
r = btrfs_subvol_remove("/xxxtest2", BTRFS_REMOVE_QUOTA);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
r = btrfs_subvol_remove("/xxxtest3", false);
r = btrfs_subvol_remove("/xxxtest3", BTRFS_REMOVE_QUOTA);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
@@ -96,7 +96,7 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to make snapshot: %m");
r = btrfs_subvol_remove("/etc2", false);
r = btrfs_subvol_remove("/etc2", BTRFS_REMOVE_QUOTA);
if (r < 0)
log_error_errno(r, "Failed to remove subvolume: %m");
@@ -137,13 +137,61 @@ int main(int argc, char *argv[]) {
if (r < 0)
log_error_errno(r, "Failed to snapshot subvolume: %m");
r = btrfs_subvol_remove("/xxxrectest", true);
r = btrfs_subvol_remove("/xxxrectest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
if (r < 0)
log_error_errno(r, "Failed to recursively remove subvolume: %m");
r = btrfs_subvol_remove("/xxxrectest2", true);
r = btrfs_subvol_remove("/xxxrectest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
if (r < 0)
log_error_errno(r, "Failed to recursively remove subvolume: %m");
r = btrfs_subvol_make("/xxxquotatest");
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
r = btrfs_subvol_auto_qgroup("/xxxquotatest", 0, true);
if (r < 0)
log_error_errno(r, "Failed to set up auto qgroup: %m");
r = btrfs_subvol_make("/xxxquotatest/beneath");
if (r < 0)
log_error_errno(r, "Failed to make subvolume: %m");
r = btrfs_subvol_auto_qgroup("/xxxquotatest/beneath", 0, false);
if (r < 0)
log_error_errno(r, "Failed to set up auto qgroup: %m");
r = btrfs_qgroup_set_limit("/xxxquotatest/beneath", 0, 4ULL * 1024 * 1024 * 1024);
if (r < 0)
log_error_errno(r, "Failed to set up quota limit: %m");
r = btrfs_subvol_set_subtree_quota_limit("/xxxquotatest", 0, 5ULL * 1024 * 1024 * 1024);
if (r < 0)
log_error_errno(r, "Failed to set up quota limit: %m");
r = btrfs_subvol_snapshot("/xxxquotatest", "/xxxquotatest2", BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA);
if (r < 0)
log_error_errno(r, "Failed to setup snapshot: %m");
r = btrfs_qgroup_get_quota("/xxxquotatest2/beneath", 0, &quota);
if (r < 0)
log_error_errno(r, "Failed to query quota: %m");
assert_se(quota.referenced_max == 4ULL * 1024 * 1024 * 1024);
r = btrfs_subvol_get_subtree_quota("/xxxquotatest2", 0, &quota);
if (r < 0)
log_error_errno(r, "Failed to query quota: %m");
assert_se(quota.referenced_max == 5ULL * 1024 * 1024 * 1024);
r = btrfs_subvol_remove("/xxxquotatest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
if (r < 0)
log_error_errno(r, "Failed remove subvolume: %m");
r = btrfs_subvol_remove("/xxxquotatest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE);
if (r < 0)
log_error_errno(r, "Failed remove subvolume: %m");
return 0;
}
+35 -8
View File
@@ -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)) {