summaryrefslogtreecommitdiff
path: root/src/basic
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic')
-rw-r--r--src/basic/btrfs-util.c63
-rw-r--r--src/basic/btrfs-util.h3
-rw-r--r--src/basic/missing.h8
-rw-r--r--src/basic/strv.c9
-rw-r--r--src/basic/strv.h4
-rw-r--r--src/basic/util.c54
-rw-r--r--src/basic/util.h15
7 files changed, 143 insertions, 13 deletions
diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c
index 074deeccda..ec7e00986b 100644
--- a/src/basic/btrfs-util.c
+++ b/src/basic/btrfs-util.c
@@ -799,6 +799,45 @@ int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) {
return btrfs_resize_loopback_fd(fd, new_size, grow_only);
}
+static int make_qgroup_id(uint64_t level, uint64_t id, uint64_t *ret) {
+ assert(ret);
+
+ if (level >= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT)))
+ return -EINVAL;
+
+ if (id >= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT))
+ return -EINVAL;
+
+ *ret = (level << BTRFS_QGROUP_LEVEL_SHIFT) | id;
+ return 0;
+}
+
+static int qgroup_create_or_destroy(int fd, bool b, uint64_t level, uint64_t id) {
+
+ struct btrfs_ioctl_qgroup_create_args args = {
+ .create = b,
+ };
+
+ int r;
+
+ r = make_qgroup_id(level, id, (uint64_t*) &args.qgroupid);
+ if (r < 0)
+ return r;
+
+ if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int btrfs_qgroup_create(int fd, uint64_t level, uint64_t id) {
+ return qgroup_create_or_destroy(fd, true, level, id);
+}
+
+int btrfs_qgroup_destroy(int fd, uint64_t level, uint64_t id) {
+ return qgroup_create_or_destroy(fd, false, level, id);
+}
+
static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, bool recursive) {
struct btrfs_ioctl_search_args args = {
.key.tree_id = BTRFS_ROOT_TREE_OBJECTID,
@@ -828,16 +867,6 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
if (!S_ISDIR(st.st_mode))
return -EINVAL;
- /* First, try to remove the subvolume. If it happens to be
- * already empty, this will just work. */
- strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
- if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0)
- return 0;
- if (!recursive || errno != ENOTEMPTY)
- return -errno;
-
- /* OK, the subvolume is not empty, let's look for child
- * subvolumes, and remove them, first */
subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
if (subvol_fd < 0)
return -errno;
@@ -848,6 +877,19 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
return r;
}
+ /* First, try to remove the subvolume. If it happens to be
+ * already empty, this will just work. */
+ strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1);
+ if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0) {
+ (void) btrfs_qgroup_destroy(fd, 0, subvol_id);
+ return 0;
+ }
+ if (!recursive || errno != ENOTEMPTY)
+ return -errno;
+
+ /* OK, the subvolume is not empty, let's look for child
+ * subvolumes, and remove them, first */
+
args.key.min_offset = args.key.max_offset = subvol_id;
while (btrfs_ioctl_search_args_compare(&args) <= 0) {
@@ -925,6 +967,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol
if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) < 0)
return -errno;
+ (void) btrfs_qgroup_destroy(fd, 0, subvol_id);
return 0;
}
diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h
index 8632c3638c..ad7c7009ab 100644
--- a/src/basic/btrfs-util.h
+++ b/src/basic/btrfs-util.h
@@ -86,3 +86,6 @@ 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_qgroup_create(int fd, uint64_t level, uint64_t id);
+int btrfs_qgroup_destroy(int fd, uint64_t level, uint64_t id);
diff --git a/src/basic/missing.h b/src/basic/missing.h
index 59e835a466..70d6c8308e 100644
--- a/src/basic/missing.h
+++ b/src/basic/missing.h
@@ -126,6 +126,10 @@
#define SOL_NETLINK 270
#endif
+#ifndef NETLINK_LIST_MEMBERSHIPS
+#define NETLINK_LIST_MEMBERSHIPS 9
+#endif
+
#if !HAVE_DECL_PIVOT_ROOT
static inline int pivot_root(const char *new_root, const char *put_old) {
return syscall(SYS_pivot_root, new_root, put_old);
@@ -248,6 +252,10 @@ static inline int getrandom(void *buffer, size_t count, unsigned flags) {
#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
#endif
+#ifndef BTRFS_QGROUP_LEVEL_SHIFT
+#define BTRFS_QGROUP_LEVEL_SHIFT 48
+#endif
+
#ifndef HAVE_LINUX_BTRFS_H
struct btrfs_ioctl_vol_args {
int64_t fd;
diff --git a/src/basic/strv.c b/src/basic/strv.c
index b66c176487..501d022cb9 100644
--- a/src/basic/strv.c
+++ b/src/basic/strv.c
@@ -86,6 +86,15 @@ char **strv_free(char **l) {
return NULL;
}
+char **strv_free_erase(char **l) {
+ char **i;
+
+ STRV_FOREACH(i, l)
+ string_erase(*i);
+
+ return strv_free(l);
+}
+
char **strv_copy(char * const *l) {
char **r, **k;
diff --git a/src/basic/strv.h b/src/basic/strv.h
index e49f443835..a5dc696a87 100644
--- a/src/basic/strv.h
+++ b/src/basic/strv.h
@@ -35,6 +35,10 @@ char **strv_free(char **l);
DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free);
#define _cleanup_strv_free_ _cleanup_(strv_freep)
+char **strv_free_erase(char **l);
+DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase);
+#define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep)
+
void strv_clear(char **l);
char **strv_copy(char * const *l);
diff --git a/src/basic/util.c b/src/basic/util.c
index 8b896a2df3..3e90456dd3 100644
--- a/src/basic/util.c
+++ b/src/basic/util.c
@@ -29,6 +29,7 @@
#include <libintl.h>
#include <limits.h>
#include <linux/magic.h>
+#include <linux/oom.h>
#include <linux/sched.h>
#include <locale.h>
#include <netinet/ip.h>
@@ -2499,11 +2500,35 @@ char *getusername_malloc(void) {
return lookup_uid(getuid());
}
-bool is_temporary_fs(const struct statfs *s) {
+bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) {
assert(s);
+ assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type));
+
+ return F_TYPE_EQUAL(s->f_type, magic_value);
+}
+
+int fd_check_fstype(int fd, statfs_f_type_t magic_value) {
+ struct statfs s;
+
+ if (fstatfs(fd, &s) < 0)
+ return -errno;
+
+ return is_fs_type(&s, magic_value);
+}
+
+int path_check_fstype(const char *path, statfs_f_type_t magic_value) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return -errno;
+
+ return fd_check_fstype(fd, magic_value);
+}
- return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
- F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
+bool is_temporary_fs(const struct statfs *s) {
+ return is_fs_type(s, TMPFS_MAGIC) ||
+ is_fs_type(s, RAMFS_MAGIC);
}
int fd_is_temporary_fs(int fd) {
@@ -6800,3 +6825,26 @@ bool fdname_is_valid(const char *s) {
return p - s < 256;
}
+
+bool oom_score_adjust_is_valid(int oa) {
+ return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX;
+}
+
+void string_erase(char *x) {
+
+ if (!x)
+ return;
+
+ /* A delicious drop of snake-oil! To be called on memory where
+ * we stored passphrases or so, after we used them. */
+
+ memory_erase(x, strlen(x));
+}
+
+char *string_free_erase(char *s) {
+ if (!s)
+ return NULL;
+
+ string_erase(s);
+ return mfree(s);
+}
diff --git a/src/basic/util.h b/src/basic/util.h
index 2544ad0830..ff39eae715 100644
--- a/src/basic/util.h
+++ b/src/basic/util.h
@@ -365,6 +365,12 @@ char* getusername_malloc(void);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
+typedef long statfs_f_type_t;
+
+bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_;
+int fd_check_fstype(int fd, statfs_f_type_t magic_value);
+int path_check_fstype(const char *path, statfs_f_type_t magic_value);
+
bool is_temporary_fs(const struct statfs *s) _pure_;
int fd_is_temporary_fs(int fd);
@@ -941,3 +947,12 @@ void nop_signal_handler(int sig);
int version(void);
bool fdname_is_valid(const char *s);
+
+bool oom_score_adjust_is_valid(int oa);
+
+#define memory_erase(p, l) memset((p), 'x', (l))
+void string_erase(char *x);
+
+char *string_free_erase(char *s);
+DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase);
+#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep)