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>
master
Omar Sandoval 2018-01-18 13:09:32 -08:00 committed by David Sterba
parent 23c01b3c1b
commit bad4208da3
8 changed files with 367 additions and 1 deletions

View File

@ -135,7 +135,7 @@ libbtrfsutil_major := $(shell sed -rn 's/^\#define BTRFS_UTIL_VERSION_MAJOR ([0-
libbtrfsutil_minor := $(shell sed -rn 's/^\#define BTRFS_UTIL_VERSION_MINOR ([0-9])+$$/\1/p' libbtrfsutil/btrfsutil.h)
libbtrfsutil_patch := $(shell sed -rn 's/^\#define BTRFS_UTIL_VERSION_PATCH ([0-9])+$$/\1/p' libbtrfsutil/btrfsutil.h)
libbtrfsutil_version := $(libbtrfsutil_major).$(libbtrfsutil_minor).$(libbtrfsutil_patch)
libbtrfsutil_objects = libbtrfsutil/errors.o
libbtrfsutil_objects = libbtrfsutil/errors.o libbtrfsutil/qgroup.o
convert_objects = convert/main.o convert/common.o convert/source-fs.o \
convert/source-ext2.o convert/source-reiserfs.o
mkfs_objects = mkfs/main.o mkfs/common.o mkfs/rootdir.o

View File

@ -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

View File

@ -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.

View File

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

View File

@ -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 */
};

View File

@ -91,6 +91,7 @@ module = Extension(
'constants.c',
'error.c',
'module.c',
'qgroup.c',
],
include_dirs=['..'],
library_dirs=['../..'],

View File

@ -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])

View File

@ -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;
}