summaryrefslogtreecommitdiff
path: root/libbtrfsutil
diff options
context:
space:
mode:
authorOmar Sandoval <osandov@fb.com>2018-01-18 13:09:32 -0800
committerDavid Sterba <dsterba@suse.com>2018-02-24 01:37:17 +0100
commitbad4208da33f3ef2adf9af2b06a597f2ce23d228 (patch)
tree691e65ddd839a3cb80fb79f288a4eb55b896f007 /libbtrfsutil
parent23c01b3c1b0803950657f3f29914cd59f3554a84 (diff)
libbtrfsutil: add qgroup inheritance helpers
We want to hide struct btrfs_qgroup_inherit from the user because that comes from the Btrfs UAPI headers. Instead, wrap it in a struct btrfs_util_qgroup_inherit and provide helpers to manipulate it. This will be used for subvolume and snapshot creation. Signed-off-by: Omar Sandoval <osandov@fb.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'libbtrfsutil')
-rw-r--r--libbtrfsutil/btrfsutil.h78
-rw-r--r--libbtrfsutil/python/btrfsutilpy.h6
-rw-r--r--libbtrfsutil/python/module.c8
-rw-r--r--libbtrfsutil/python/qgroup.c154
-rwxr-xr-xlibbtrfsutil/python/setup.py1
-rw-r--r--libbtrfsutil/python/tests/test_qgroup.py36
-rw-r--r--libbtrfsutil/qgroup.c83
7 files changed, 366 insertions, 0 deletions
diff --git a/libbtrfsutil/btrfsutil.h b/libbtrfsutil/btrfsutil.h
index 867418f..76bf0b6 100644
--- a/libbtrfsutil/btrfsutil.h
+++ b/libbtrfsutil/btrfsutil.h
@@ -20,6 +20,9 @@
#ifndef BTRFS_UTIL_H
#define BTRFS_UTIL_H
+#include <stddef.h>
+#include <stdint.h>
+
#define BTRFS_UTIL_VERSION_MAJOR 1
#define BTRFS_UTIL_VERSION_MINOR 0
#define BTRFS_UTIL_VERSION_PATCH 0
@@ -69,6 +72,81 @@ enum btrfs_util_error {
*/
const char *btrfs_util_strerror(enum btrfs_util_error err);
+/**
+ * btrfs_util_is_subvolume() - Return whether a given path is a Btrfs subvolume.
+ * @path: Path to check.
+ *
+ * Return: %BTRFS_UTIL_OK if @path is a Btrfs subvolume,
+ * %BTRFS_UTIL_ERROR_NOT_BTRFS if @path is not on a Btrfs filesystem,
+ * %BTRFS_UTIL_ERROR_NOT_SUBVOLUME if @path is not a subvolume, non-zero error
+ * code on any other failure.
+ */
+enum btrfs_util_error btrfs_util_is_subvolume(const char *path);
+
+/**
+ * btrfs_util_is_subvolume_fd() - See btrfs_util_is_subvolume().
+ */
+enum btrfs_util_error btrfs_util_is_subvolume_fd(int fd);
+
+/**
+ * btrfs_util_subvolume_id() - Get the ID of the subvolume containing a path.
+ * @path: Path on a Btrfs filesystem.
+ * @id_ret: Returned subvolume ID.
+ *
+ * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure.
+ */
+enum btrfs_util_error btrfs_util_subvolume_id(const char *path,
+ uint64_t *id_ret);
+
+/**
+ * btrfs_util_subvolume_id_fd() - See btrfs_util_subvolume_id().
+ */
+enum btrfs_util_error btrfs_util_subvolume_id_fd(int fd, uint64_t *id_ret);
+
+struct btrfs_util_qgroup_inherit;
+
+/**
+ * btrfs_util_create_qgroup_inherit() - Create a qgroup inheritance specifier
+ * for btrfs_util_create_subvolume() or btrfs_util_create_snapshot().
+ * @flags: Must be zero.
+ * @ret: Returned qgroup inheritance specifier.
+ *
+ * The returned structure must be freed with
+ * btrfs_util_destroy_qgroup_inherit().
+ *
+ * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure.
+ */
+enum btrfs_util_error btrfs_util_create_qgroup_inherit(int flags,
+ struct btrfs_util_qgroup_inherit **ret);
+
+/**
+ * btrfs_util_destroy_qgroup_inherit() - Destroy a qgroup inheritance specifier
+ * previously created with btrfs_util_create_qgroup_inherit().
+ * @inherit: Specifier to destroy.
+ */
+void btrfs_util_destroy_qgroup_inherit(struct btrfs_util_qgroup_inherit *inherit);
+
+/**
+ * btrfs_util_qgroup_inherit_add_group() - Add inheritance from a qgroup to a
+ * qgroup inheritance specifier.
+ * @inherit: Specifier to modify. May be reallocated.
+ * @qgroupid: ID of qgroup to inherit from.
+ *
+ * Return: %BTRFS_UTIL_OK on success, non-zero error code on failure.
+ */
+enum btrfs_util_error btrfs_util_qgroup_inherit_add_group(struct btrfs_util_qgroup_inherit **inherit,
+ uint64_t qgroupid);
+
+/**
+ * btrfs_util_qgroup_inherit_get_groups() - Get the qgroups a qgroup inheritance
+ * specifier contains.
+ * @inherit: Qgroup inheritance specifier.
+ * @groups: Returned array of qgroup IDs.
+ * @n: Returned number of entries in the @groups array.
+ */
+void btrfs_util_qgroup_inherit_get_groups(const struct btrfs_util_qgroup_inherit *inherit,
+ const uint64_t **groups, size_t *n);
+
#ifdef __cplusplus
}
#endif
diff --git a/libbtrfsutil/python/btrfsutilpy.h b/libbtrfsutil/python/btrfsutilpy.h
index 6d82f7e..3b5d784 100644
--- a/libbtrfsutil/python/btrfsutilpy.h
+++ b/libbtrfsutil/python/btrfsutilpy.h
@@ -29,7 +29,13 @@
#include <btrfsutil.h>
+typedef struct {
+ PyObject_HEAD
+ struct btrfs_util_qgroup_inherit *inherit;
+} QgroupInherit;
+
extern PyTypeObject BtrfsUtilError_type;
+extern PyTypeObject QgroupInherit_type;
/*
* Helpers for path arguments based on posixmodule.c in CPython.
diff --git a/libbtrfsutil/python/module.c b/libbtrfsutil/python/module.c
index d739880..24d962d 100644
--- a/libbtrfsutil/python/module.c
+++ b/libbtrfsutil/python/module.c
@@ -152,6 +152,10 @@ PyInit_btrfsutil(void)
if (PyType_Ready(&BtrfsUtilError_type) < 0)
return NULL;
+ QgroupInherit_type.tp_new = PyType_GenericNew;
+ if (PyType_Ready(&QgroupInherit_type) < 0)
+ return NULL;
+
m = PyModule_Create(&btrfsutilmodule);
if (!m)
return NULL;
@@ -160,6 +164,10 @@ PyInit_btrfsutil(void)
PyModule_AddObject(m, "BtrfsUtilError",
(PyObject *)&BtrfsUtilError_type);
+ Py_INCREF(&QgroupInherit_type);
+ PyModule_AddObject(m, "QgroupInherit",
+ (PyObject *)&QgroupInherit_type);
+
add_module_constants(m);
return m;
diff --git a/libbtrfsutil/python/qgroup.c b/libbtrfsutil/python/qgroup.c
new file mode 100644
index 0000000..69716d9
--- /dev/null
+++ b/libbtrfsutil/python/qgroup.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2018 Facebook
+ *
+ * This file is part of libbtrfsutil.
+ *
+ * libbtrfsutil is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * libbtrfsutil is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libbtrfsutil. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "btrfsutilpy.h"
+
+static void QgroupInherit_dealloc(QgroupInherit *self)
+{
+ btrfs_util_destroy_qgroup_inherit(self->inherit);
+ Py_TYPE(self)->tp_free((PyObject *)self);
+}
+
+static int QgroupInherit_init(QgroupInherit *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *keywords[] = {NULL};
+ enum btrfs_util_error err;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, ":QgroupInherit",
+ keywords))
+ return -1;
+
+ err = btrfs_util_create_qgroup_inherit(0, &self->inherit);
+ if (err) {
+ SetFromBtrfsUtilError(err);
+ return -1;
+ }
+
+ return 0;
+}
+
+static PyObject *QgroupInherit_getattro(QgroupInherit *self, PyObject *nameobj)
+{
+ const char *name = "";
+
+ if (PyUnicode_Check(nameobj)) {
+ name = PyUnicode_AsUTF8(nameobj);
+ if (!name)
+ return NULL;
+ }
+
+ if (strcmp(name, "groups") == 0) {
+ PyObject *ret, *tmp;
+ const uint64_t *arr;
+ size_t n, i;
+
+ btrfs_util_qgroup_inherit_get_groups(self->inherit, &arr, &n);
+ ret = PyList_New(n);
+ if (!ret)
+ return NULL;
+
+ for (i = 0; i < n; i++) {
+ tmp = PyLong_FromUnsignedLongLong(arr[i]);
+ if (!tmp) {
+ Py_DECREF(ret);
+ return NULL;
+ }
+ PyList_SET_ITEM(ret, i, tmp);
+ }
+
+ return ret;
+ } else {
+ return PyObject_GenericGetAttr((PyObject *)self, nameobj);
+ }
+}
+
+static PyObject *QgroupInherit_add_group(QgroupInherit *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *keywords[] = {"qgroupid", NULL};
+ enum btrfs_util_error err;
+ uint64_t qgroupid;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "K:add_group", keywords,
+ &qgroupid))
+ return NULL;
+
+ err = btrfs_util_qgroup_inherit_add_group(&self->inherit, qgroupid);
+ if (err) {
+ SetFromBtrfsUtilError(err);
+ return NULL;
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef QgroupInherit_methods[] = {
+ {"add_group", (PyCFunction)QgroupInherit_add_group,
+ METH_VARARGS | METH_KEYWORDS,
+ "add_group(qgroupid)\n\n"
+ "Add a qgroup to inherit from.\n\n"
+ "Arguments:\n"
+ "qgroupid -- ID of qgroup to add"},
+ {},
+};
+
+#define QgroupInherit_DOC \
+ "QgroupInherit() -> new qgroup inheritance specifier\n\n" \
+ "Create a new object which specifies what qgroups to inherit\n" \
+ "from for create_subvolume() and create_snapshot()"
+
+PyTypeObject QgroupInherit_type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "btrfsutil.QgroupInherit", /* tp_name */
+ sizeof(QgroupInherit), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)QgroupInherit_dealloc, /* tp_dealloc */
+ NULL, /* tp_print */
+ NULL, /* tp_getattr */
+ NULL, /* tp_setattr */
+ NULL, /* tp_as_async */
+ NULL, /* tp_repr */
+ NULL, /* tp_as_number */
+ NULL, /* tp_as_sequence */
+ NULL, /* tp_as_mapping */
+ NULL, /* tp_hash */
+ NULL, /* tp_call */
+ NULL, /* tp_str */
+ (getattrofunc)QgroupInherit_getattro, /* tp_getattro */
+ NULL, /* tp_setattro */
+ NULL, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ QgroupInherit_DOC, /* tp_doc */
+ NULL, /* tp_traverse */
+ NULL, /* tp_clear */
+ NULL, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ NULL, /* tp_iter */
+ NULL, /* tp_iternext */
+ QgroupInherit_methods, /* tp_methods */
+ NULL, /* tp_members */
+ NULL, /* tp_getset */
+ NULL, /* tp_base */
+ NULL, /* tp_dict */
+ NULL, /* tp_descr_get */
+ NULL, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)QgroupInherit_init, /* tp_init */
+};
diff --git a/libbtrfsutil/python/setup.py b/libbtrfsutil/python/setup.py
index 6f04a6f..478510c 100755
--- a/libbtrfsutil/python/setup.py
+++ b/libbtrfsutil/python/setup.py
@@ -91,6 +91,7 @@ module = Extension(
'constants.c',
'error.c',
'module.c',
+ 'qgroup.c',
],
include_dirs=['..'],
library_dirs=['../..'],
diff --git a/libbtrfsutil/python/tests/test_qgroup.py b/libbtrfsutil/python/tests/test_qgroup.py
new file mode 100644
index 0000000..a590464
--- /dev/null
+++ b/libbtrfsutil/python/tests/test_qgroup.py
@@ -0,0 +1,36 @@
+# Copyright (C) 2018 Facebook
+#
+# This file is part of libbtrfsutil.
+#
+# libbtrfsutil is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# libbtrfsutil is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with libbtrfsutil. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import unittest
+
+import btrfsutil
+
+
+class TestQgroupInherit(unittest.TestCase):
+ def test_new(self):
+ inherit = btrfsutil.QgroupInherit()
+ self.assertEqual(inherit.groups, [])
+
+ def test_add_group(self):
+ inherit = btrfsutil.QgroupInherit()
+ inherit.add_group(1)
+ self.assertEqual(inherit.groups, [1])
+ inherit.add_group(2)
+ self.assertEqual(inherit.groups, [1, 2])
+ inherit.add_group(3)
+ self.assertEqual(inherit.groups, [1, 2, 3])
diff --git a/libbtrfsutil/qgroup.c b/libbtrfsutil/qgroup.c
new file mode 100644
index 0000000..d291618
--- /dev/null
+++ b/libbtrfsutil/qgroup.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2018 Facebook
+ *
+ * This file is part of libbtrfsutil.
+ *
+ * libbtrfsutil is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * libbtrfsutil is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with libbtrfsutil. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/btrfs.h>
+
+#include "btrfsutil_internal.h"
+
+PUBLIC enum btrfs_util_error btrfs_util_create_qgroup_inherit(int flags,
+ struct btrfs_util_qgroup_inherit **ret)
+{
+ struct btrfs_qgroup_inherit *inherit;
+
+ if (flags) {
+ errno = EINVAL;
+ return BTRFS_UTIL_ERROR_INVALID_ARGUMENT;
+ }
+
+ inherit = calloc(1, sizeof(*inherit));
+ if (!inherit)
+ return BTRFS_UTIL_ERROR_NO_MEMORY;
+
+ /*
+ * struct btrfs_util_qgroup_inherit is a lie; it's actually struct
+ * btrfs_qgroup_inherit, but we abstract it away so that users don't
+ * need to depend on the Btrfs UAPI headers.
+ */
+ *ret = (struct btrfs_util_qgroup_inherit *)inherit;
+
+ return BTRFS_UTIL_OK;
+}
+
+PUBLIC void btrfs_util_destroy_qgroup_inherit(struct btrfs_util_qgroup_inherit *inherit)
+{
+ free(inherit);
+}
+
+PUBLIC enum btrfs_util_error btrfs_util_qgroup_inherit_add_group(struct btrfs_util_qgroup_inherit **inherit,
+ uint64_t qgroupid)
+{
+ struct btrfs_qgroup_inherit *tmp = (struct btrfs_qgroup_inherit *)*inherit;
+
+ tmp = realloc(tmp, sizeof(*tmp) +
+ (tmp->num_qgroups + 1) * sizeof(tmp->qgroups[0]));
+ if (!tmp)
+ return BTRFS_UTIL_ERROR_NO_MEMORY;
+
+ tmp->qgroups[tmp->num_qgroups++] = qgroupid;
+
+ *inherit = (struct btrfs_util_qgroup_inherit *)tmp;
+
+ return BTRFS_UTIL_OK;
+}
+
+PUBLIC void btrfs_util_qgroup_inherit_get_groups(const struct btrfs_util_qgroup_inherit *inherit,
+ const uint64_t **groups,
+ size_t *n)
+{
+ struct btrfs_qgroup_inherit *tmp = (struct btrfs_qgroup_inherit *)inherit;
+
+ /* Need to cast because __u64 != uint64_t. */
+ *groups = (const uint64_t *)&tmp->qgroups[0];
+ *n = tmp->num_qgroups;
+}