linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Nikolay Borisov <nborisov@suse.com>
To: Omar Sandoval <osandov@osandov.com>, linux-btrfs@vger.kernel.org
Cc: kernel-team@fb.com
Subject: Re: [PATCH 04/26] libbtrfsutil: add btrfs_util_is_subvolume() and btrfs_util_subvolume_id()
Date: Mon, 29 Jan 2018 12:24:26 +0200	[thread overview]
Message-ID: <c1c4fa63-7ab5-ad6a-d1a4-066ac58be161@suse.com> (raw)
In-Reply-To: <ec89f2b55edb450ce4fcbe1485ae8f57ed51187c.1516991902.git.osandov@fb.com>



On 26.01.2018 20:40, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
> 
> These are the most trivial helpers in the library and will be used to
> implement several of the more involved functions.
> 
> Signed-off-by: Omar Sandoval <osandov@fb.com>
> ---
>  Makefile                                    |   2 +-
>  libbtrfsutil/btrfsutil.h                    |  33 +++++++
>  libbtrfsutil/python/btrfsutilpy.h           |   3 +
>  libbtrfsutil/python/module.c                |  12 +++
>  libbtrfsutil/python/setup.py                |   1 +
>  libbtrfsutil/python/subvolume.c             |  73 +++++++++++++++
>  libbtrfsutil/python/tests/__init__.py       |  66 ++++++++++++++
>  libbtrfsutil/python/tests/test_subvolume.py |  57 ++++++++++++
>  libbtrfsutil/subvolume.c                    | 137 ++++++++++++++++++++++++++++
>  9 files changed, 383 insertions(+), 1 deletion(-)
>  create mode 100644 libbtrfsutil/python/subvolume.c
>  create mode 100644 libbtrfsutil/python/tests/test_subvolume.py
>  create mode 100644 libbtrfsutil/subvolume.c
> 
> diff --git a/Makefile b/Makefile
> index 02b03e81..48a558a9 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -123,7 +123,7 @@ libbtrfs_headers = send-stream.h send-utils.h send.h kernel-lib/rbtree.h btrfs-l
>  	       kernel-lib/radix-tree.h kernel-lib/sizes.h kernel-lib/raid56.h \
>  	       extent-cache.h extent_io.h ioctl.h ctree.h btrfsck.h version.h
>  libbtrfsutil_version := 0.1
> -libbtrfsutil_objects = libbtrfsutil/errors.o
> +libbtrfsutil_objects = libbtrfsutil/errors.o libbtrfsutil/subvolume.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
> diff --git a/libbtrfsutil/btrfsutil.h b/libbtrfsutil/btrfsutil.h
> index fe1091ca..dff6599d 100644
> --- a/libbtrfsutil/btrfsutil.h
> +++ b/libbtrfsutil/btrfsutil.h
> @@ -20,6 +20,8 @@
>  #ifndef BTRFS_UTIL_H
>  #define BTRFS_UTIL_H
>  
> +#include <stdint.h>
> +
>  #ifdef __cplusplus
>  extern "C" {
>  #endif
> @@ -65,6 +67,37 @@ 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_f_is_subvolume() - See btrfs_util_is_subvolume().
> + */
> +enum btrfs_util_error btrfs_util_f_is_subvolume(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_f_subvolume_id() - See btrfs_util_subvolume_id().
> + */
> +enum btrfs_util_error btrfs_util_f_subvolume_id(int fd, uint64_t *id_ret);
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/libbtrfsutil/python/btrfsutilpy.h b/libbtrfsutil/python/btrfsutilpy.h
> index 6d82f7e1..9a04fda7 100644
> --- a/libbtrfsutil/python/btrfsutilpy.h
> +++ b/libbtrfsutil/python/btrfsutilpy.h
> @@ -52,6 +52,9 @@ void SetFromBtrfsUtilErrorWithPaths(enum btrfs_util_error err,
>  				    struct path_arg *path1,
>  				    struct path_arg *path2);
>  
> +PyObject *is_subvolume(PyObject *self, PyObject *args, PyObject *kwds);
> +PyObject *subvolume_id(PyObject *self, PyObject *args, PyObject *kwds);
> +
>  void add_module_constants(PyObject *m);
>  
>  #endif /* BTRFSUTILPY_H */
> diff --git a/libbtrfsutil/python/module.c b/libbtrfsutil/python/module.c
> index d7398808..d492cbc7 100644
> --- a/libbtrfsutil/python/module.c
> +++ b/libbtrfsutil/python/module.c
> @@ -132,6 +132,18 @@ void path_cleanup(struct path_arg *path)
>  }
>  
>  static PyMethodDef btrfsutil_methods[] = {
> +	{"is_subvolume", (PyCFunction)is_subvolume,
> +	 METH_VARARGS | METH_KEYWORDS,
> +	 "is_subvolume(path) -> bool\n\n"
> +	 "Get whether a file is a subvolume.\n\n"
> +	 "Arguments:\n"
> +	 "path -- string, bytes, path-like object, or open file descriptor"},
> +	{"subvolume_id", (PyCFunction)subvolume_id,
> +	 METH_VARARGS | METH_KEYWORDS,
> +	 "subvolume_id(path) -> int\n\n"
> +	 "Get the ID of the subvolume containing a file.\n\n"
> +	 "Arguments:\n"
> +	 "path -- string, bytes, path-like object, or open file descriptor"},
>  	{},
>  };
>  
> diff --git a/libbtrfsutil/python/setup.py b/libbtrfsutil/python/setup.py
> index 3dc778ab..be973a34 100755
> --- a/libbtrfsutil/python/setup.py
> +++ b/libbtrfsutil/python/setup.py
> @@ -79,6 +79,7 @@ module = Extension(
>          'constants.c',
>          'error.c',
>          'module.c',
> +        'subvolume.c',
>      ],
>      include_dirs=['..'],
>      library_dirs=['../..'],
> diff --git a/libbtrfsutil/python/subvolume.c b/libbtrfsutil/python/subvolume.c
> new file mode 100644
> index 00000000..538bf324
> --- /dev/null
> +++ b/libbtrfsutil/python/subvolume.c
> @@ -0,0 +1,73 @@
> +/*
> + * 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"
> +
> +PyObject *is_subvolume(PyObject *self, PyObject *args, PyObject *kwds)
> +{
> +	static char *keywords[] = {"path", NULL};
> +	struct path_arg path = {.allow_fd = true};
> +	enum btrfs_util_error err;
> +
> +	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:is_subvolume",
> +					 keywords, &path_converter, &path))
> +		return NULL;
> +
> +	if (path.path)
> +		err = btrfs_util_is_subvolume(path.path);
> +	else
> +		err = btrfs_util_f_is_subvolume(path.fd);
> +	if (err == BTRFS_UTIL_OK) {
> +		path_cleanup(&path);
> +		Py_RETURN_TRUE;
> +	} else if (err == BTRFS_UTIL_ERROR_NOT_BTRFS ||
> +		   err == BTRFS_UTIL_ERROR_NOT_SUBVOLUME) {
> +		path_cleanup(&path);
> +		Py_RETURN_FALSE;
> +	} else {
> +		SetFromBtrfsUtilErrorWithPath(err, &path);
> +		path_cleanup(&path);
> +		return NULL;
> +	}
> +}
> +
> +PyObject *subvolume_id(PyObject *self, PyObject *args, PyObject *kwds)
> +{
> +	static char *keywords[] = {"path", NULL};
> +	struct path_arg path = {.allow_fd = true};
> +	enum btrfs_util_error err;
> +	uint64_t id;
> +
> +	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:subvolume_id",
> +					 keywords, &path_converter, &path))
> +		return NULL;
> +
> +	if (path.path)
> +		err = btrfs_util_subvolume_id(path.path, &id);
> +	else
> +		err = btrfs_util_f_subvolume_id(path.fd, &id);
> +	if (err) {
> +		SetFromBtrfsUtilErrorWithPath(err, &path);
> +		path_cleanup(&path);
> +		return NULL;
> +	}
> +
> +	path_cleanup(&path);
> +	return PyLong_FromUnsignedLongLong(id);
> +}
> diff --git a/libbtrfsutil/python/tests/__init__.py b/libbtrfsutil/python/tests/__init__.py
> index e69de29b..d2c6ff28 100644
> --- a/libbtrfsutil/python/tests/__init__.py
> +++ b/libbtrfsutil/python/tests/__init__.py
> @@ -0,0 +1,66 @@
> +# 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
> +from pathlib import PurePath
> +import subprocess
> +import tempfile
> +import unittest
> +
> +
> +HAVE_PATH_LIKE = hasattr(PurePath, '__fspath__')
> +
> +
> +@unittest.skipIf(os.geteuid() != 0, 'must be run as root')
> +class BtrfsTestCase(unittest.TestCase):
> +    def setUp(self):
> +        self.mountpoint = tempfile.mkdtemp()
> +        try:
> +            with tempfile.NamedTemporaryFile(delete=False) as f:
> +                os.truncate(f.fileno(), 1024 * 1024 * 1024)
> +                self.image = f.name
> +        except Exception as e:
> +            os.rmdir(self.mountpoint)
> +            raise e
> +
> +        try:
> +            subprocess.check_call(['mkfs.btrfs', '-q', self.image])
> +            subprocess.check_call(['mount', '-o', 'loop', '--', self.image, self.mountpoint])
> +        except Exception as e:
> +            os.remove(self.image)
> +            os.rmdir(self.mountpoint)
> +            raise e
> +
> +    def tearDown(self):
> +        try:
> +            subprocess.check_call(['umount', self.mountpoint])
> +        finally:
> +            os.remove(self.image)
> +            os.rmdir(self.mountpoint)
> +
> +    @staticmethod
> +    def path_or_fd(path, open_flags=os.O_RDONLY):
> +        yield path
> +        yield path.encode()
> +        if HAVE_PATH_LIKE:
> +            yield PurePath(path)
> +        fd = os.open(path, open_flags)
> +        try:
> +            yield fd
> +        finally:
> +            os.close(fd)
> +
> diff --git a/libbtrfsutil/python/tests/test_subvolume.py b/libbtrfsutil/python/tests/test_subvolume.py
> new file mode 100644
> index 00000000..44b1d7f0
> --- /dev/null
> +++ b/libbtrfsutil/python/tests/test_subvolume.py
> @@ -0,0 +1,57 @@
> +# 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 fcntl
> +import errno
> +import os
> +import os.path
> +from pathlib import PurePath
> +import traceback
> +
> +import btrfsutil
> +from tests import BtrfsTestCase
> +
> +
> +class TestSubvolume(BtrfsTestCase):
> +    def test_is_subvolume(self):
> +        dir = os.path.join(self.mountpoint, 'foo')
> +        os.mkdir(dir)
> +
> +        for arg in self.path_or_fd(self.mountpoint):
> +            with self.subTest(type=type(arg)):
> +                self.assertTrue(btrfsutil.is_subvolume(arg))
> +        for arg in self.path_or_fd(dir):
> +            with self.subTest(type=type(arg)):
> +                self.assertFalse(btrfsutil.is_subvolume(arg))
> +
> +        with self.assertRaises(btrfsutil.BtrfsUtilError) as e:
> +            btrfsutil.is_subvolume(os.path.join(self.mountpoint, 'bar'))
> +        # This is a bit of an implementation detail, but really this is testing
> +        # that the exception is initialized correctly.
> +        self.assertEqual(e.exception.btrfsutilerror, btrfsutil.ERROR_STATFS_FAILED)
> +        self.assertEqual(e.exception.errno, errno.ENOENT)
> +
> +    def test_subvolume_id(self):
> +        dir = os.path.join(self.mountpoint, 'foo')
> +        os.mkdir(dir)
> +
> +        for arg in self.path_or_fd(self.mountpoint):
> +            with self.subTest(type=type(arg)):
> +                self.assertEqual(btrfsutil.subvolume_id(arg), 5)
> +        for arg in self.path_or_fd(dir):
> +            with self.subTest(type=type(arg)):
> +                self.assertEqual(btrfsutil.subvolume_id(arg), 5)
> diff --git a/libbtrfsutil/subvolume.c b/libbtrfsutil/subvolume.c
> new file mode 100644
> index 00000000..37d5d388
> --- /dev/null
> +++ b/libbtrfsutil/subvolume.c
> @@ -0,0 +1,137 @@
> +/*
> + * 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 <fcntl.h>
> +#include <unistd.h>
> +#include <sys/ioctl.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <sys/vfs.h>
> +#include <linux/btrfs.h>
> +#include <linux/btrfs_tree.h>
> +#include <linux/magic.h>
> +
> +#include "btrfsutil.h"
> +
> +#define SAVE_ERRNO_AND_CLOSE(fd) {	\
> +	int saved_errno = errno;	\
> +					\
> +	close(fd);			\
> +	errno = saved_errno;		\
> +}
> +
> +/*
> + * This intentionally duplicates btrfs_util_f_is_subvolume() instead of opening
> + * a file descriptor and calling it, because fstat() and fstatfs() don't accept
> + * file descriptors opened with O_PATH on old kernels (before v3.6 and before
> + * v3.12, respectively), but stat() and statfs() can be called on a path that
> + * the user doesn't have read or write permissions to.
> + */
> +__attribute__((visibility("default")))

Why do we need to explicitly set the attribute visibility to default,
isn't it implicitly default already?
> +enum btrfs_util_error btrfs_util_is_subvolume(const char *path)
> +{
> +	struct statfs sfs;
> +	struct stat st;
> +	int ret;
> +
> +	ret = statfs(path, &sfs);
> +	if (ret == -1)
> +		return BTRFS_UTIL_ERROR_STATFS_FAILED;
> +
> +	if (sfs.f_type != BTRFS_SUPER_MAGIC) {
> +		errno = EINVAL;
> +		return BTRFS_UTIL_ERROR_NOT_BTRFS;
> +	}
> +
> +	ret = stat(path, &st);
> +	if (ret == -1)
> +		return BTRFS_UTIL_ERROR_STAT_FAILED;
> +
> +	if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode)) {
> +		errno = EINVAL;
> +		return BTRFS_UTIL_ERROR_NOT_SUBVOLUME;
> +	}
> +
> +	return BTRFS_UTIL_OK;
> +}
> +
> +__attribute__((visibility("default")))
> +enum btrfs_util_error btrfs_util_f_is_subvolume(int fd)
> +{
> +	struct statfs sfs;
> +	struct stat st;
> +	int ret;
> +
> +	ret = fstatfs(fd, &sfs);
> +	if (ret == -1)
> +		return BTRFS_UTIL_ERROR_STATFS_FAILED;
> +
> +	if (sfs.f_type != BTRFS_SUPER_MAGIC) {
> +		errno = EINVAL;
> +		return BTRFS_UTIL_ERROR_NOT_BTRFS;
> +	}
> +
> +	ret = fstat(fd, &st);
> +	if (ret == -1)
> +		return BTRFS_UTIL_ERROR_STAT_FAILED;
> +
> +	if (st.st_ino != BTRFS_FIRST_FREE_OBJECTID || !S_ISDIR(st.st_mode)) {
> +		errno = EINVAL;
> +		return BTRFS_UTIL_ERROR_NOT_SUBVOLUME;
> +	}
> +
> +	return BTRFS_UTIL_OK;
> +}
> +
> +__attribute__((visibility("default")))
> +enum btrfs_util_error btrfs_util_subvolume_id(const char *path,
> +					      uint64_t *id_ret)
> +{
> +	enum btrfs_util_error err;
> +	int fd;
> +
> +	fd = open(path, O_RDONLY);
> +	if (fd == -1)
> +		return BTRFS_UTIL_ERROR_OPEN_FAILED;
> +
> +	err = btrfs_util_f_subvolume_id(fd, id_ret);
> +	SAVE_ERRNO_AND_CLOSE(fd);
> +	return err;
> +}
> +
> +__attribute__((visibility("default")))
> +enum btrfs_util_error btrfs_util_f_subvolume_id(int fd, uint64_t *id_ret)
> +{
> +	struct btrfs_ioctl_ino_lookup_args args = {
> +		.treeid = 0,
> +		.objectid = BTRFS_FIRST_FREE_OBJECTID,
> +	};
> +	int ret;
> +
> +	ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args);
> +	if (ret == -1) {
> +		close(fd);
> +		return BTRFS_UTIL_ERROR_INO_LOOKUP_FAILED;
> +	}
> +
> +	*id_ret = args.treeid;
> +
> +	return BTRFS_UTIL_OK;
> +}
> 

  reply	other threads:[~2018-01-29 10:24 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-26 18:40 [PATCH 00/26] btrfs-progs: introduce libbtrfsutil, "btrfs-progs as a library" Omar Sandoval
2018-01-26 18:40 ` [PATCH 01/26] btrfs-progs: get rid of undocumented qgroup inheritance options Omar Sandoval
2018-01-27  4:35   ` Qu Wenruo
2018-01-26 18:40 ` [PATCH 02/26] Add libbtrfsutil Omar Sandoval
2018-01-29  2:16   ` Qu Wenruo
2018-01-29 23:45     ` Omar Sandoval
2018-01-26 18:40 ` [PATCH 03/26] libbtrfsutil: add Python bindings Omar Sandoval
2018-01-26 18:40 ` [PATCH 04/26] libbtrfsutil: add btrfs_util_is_subvolume() and btrfs_util_subvolume_id() Omar Sandoval
2018-01-29 10:24   ` Nikolay Borisov [this message]
2018-01-29 21:43     ` Omar Sandoval
2018-01-30  6:54       ` Nikolay Borisov
2018-02-01 16:28         ` David Sterba
2018-02-02 19:14           ` Omar Sandoval
2018-01-26 18:40 ` [PATCH 05/26] libbtrfsutil: add qgroup inheritance helpers Omar Sandoval
2018-01-26 18:40 ` [PATCH 06/26] libbtrfsutil: add btrfs_util_create_subvolume() Omar Sandoval
2018-01-26 18:40 ` [PATCH 07/26] libbtrfsutil: add btrfs_util_subvolume_info() Omar Sandoval
2018-01-26 18:40 ` [PATCH 08/26] libbtrfsutil: add btrfs_util_[gs]et_read_only() Omar Sandoval
2018-01-26 18:40 ` [PATCH 09/26] libbtrfsutil: add btrfs_util_[gs]et_default_subvolume() Omar Sandoval
2018-01-26 18:40 ` [PATCH 10/26] libbtrfsutil: add subvolume iterator helpers Omar Sandoval
2018-01-26 18:40 ` [PATCH 11/26] libbtrfsutil: add btrfs_util_create_snapshot() Omar Sandoval
2018-01-26 19:31   ` Goffredo Baroncelli
2018-01-26 19:46     ` Omar Sandoval
2018-01-27  5:00       ` Qu Wenruo
2018-01-27  5:45         ` Omar Sandoval
2018-01-27 14:19           ` Goffredo Baroncelli
2018-01-27 16:31           ` Nikolay Borisov
2018-01-27 18:54             ` Omar Sandoval
2018-01-26 18:41 ` [PATCH 12/26] libbtrfsutil: add btrfs_util_delete_subvolume() Omar Sandoval
2018-01-26 18:41 ` [PATCH 13/26] libbtrfsutil: add btrfs_util_deleted_subvolumes() Omar Sandoval
2018-01-26 18:41 ` [PATCH 14/26] libbtrfsutil: add filesystem sync helpers Omar Sandoval
2018-01-26 18:41 ` [PATCH 15/26] btrfs-progs: use libbtrfsutil for read-only property Omar Sandoval
2018-01-26 18:41 ` [PATCH 16/26] btrfs-progs: use libbtrfsutil for sync ioctls Omar Sandoval
2018-01-26 18:41 ` [PATCH 17/26] btrfs-progs: use libbtrfsutil for set-default Omar Sandoval
2018-01-26 18:41 ` [PATCH 18/26] btrfs-progs: use libbtrfsutil for get-default Omar Sandoval
2018-01-26 18:41 ` [PATCH 19/26] btrfs-progs: use libbtrfsutil for subvol create and snapshot Omar Sandoval
2018-01-26 18:41 ` [PATCH 20/26] btrfs-progs: use libbtrfsutil for subvol delete Omar Sandoval
2018-01-26 18:41 ` [PATCH 21/26] btrfs-progs: use libbtrfsutil for subvol show Omar Sandoval
2018-02-02 23:18   ` Hans van Kranenburg
2018-02-02 23:29     ` Omar Sandoval
2018-01-26 18:41 ` [PATCH 22/26] btrfs-progs: use libbtrfsutil for subvol sync Omar Sandoval
2018-01-26 18:41 ` [PATCH 23/26] btrfs-progs: replace test_issubvolume() with btrfs_util_is_subvolume() Omar Sandoval
2018-01-26 18:41 ` [PATCH 24/26] btrfs-progs: add recursive snapshot/delete using libbtrfsutil Omar Sandoval
2018-01-26 18:41 ` [PATCH 25/26] btrfs-progs: deprecate libbtrfs helpers with libbtrfsutil equivalents Omar Sandoval
2018-02-02 14:49   ` David Sterba
2018-01-26 18:41 ` [PATCH 26/26] btrfs-progs: use libbtrfsutil for subvolume list Omar Sandoval
2018-01-26 18:51 ` [PATCH 00/26] btrfs-progs: introduce libbtrfsutil, "btrfs-progs as a library" Hugo Mills
2018-02-02 23:04   ` Hans van Kranenburg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c1c4fa63-7ab5-ad6a-d1a4-066ac58be161@suse.com \
    --to=nborisov@suse.com \
    --cc=kernel-team@fb.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=osandov@osandov.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).