summaryrefslogtreecommitdiff
path: root/libbtrfsutil/python
diff options
context:
space:
mode:
authorOmar Sandoval <osandov@fb.com>2018-01-25 01:18:20 -0800
committerDavid Sterba <dsterba@suse.com>2018-02-24 01:37:17 +0100
commit9615c23d1570c22a249c9eced754156e844c26b6 (patch)
tree64395b8cfe5302c2205ea1755d4434972c3ff83c /libbtrfsutil/python
parentbad4208da33f3ef2adf9af2b06a597f2ce23d228 (diff)
libbtrfsutil: add filesystem sync helpers
Namely, sync, start_sync, and wait_sync. Signed-off-by: Omar Sandoval <osandov@fb.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'libbtrfsutil/python')
-rw-r--r--libbtrfsutil/python/btrfsutilpy.h4
-rw-r--r--libbtrfsutil/python/filesystem.c94
-rw-r--r--libbtrfsutil/python/module.c21
-rwxr-xr-xlibbtrfsutil/python/setup.py1
-rw-r--r--libbtrfsutil/python/tests/test_filesystem.py73
5 files changed, 193 insertions, 0 deletions
diff --git a/libbtrfsutil/python/btrfsutilpy.h b/libbtrfsutil/python/btrfsutilpy.h
index 3b5d7849..02039ba1 100644
--- a/libbtrfsutil/python/btrfsutilpy.h
+++ b/libbtrfsutil/python/btrfsutilpy.h
@@ -58,6 +58,10 @@ void SetFromBtrfsUtilErrorWithPaths(enum btrfs_util_error err,
struct path_arg *path1,
struct path_arg *path2);
+PyObject *filesystem_sync(PyObject *self, PyObject *args, PyObject *kwds);
+PyObject *start_sync(PyObject *self, PyObject *args, PyObject *kwds);
+PyObject *wait_sync(PyObject *self, PyObject *args, PyObject *kwds);
+
void add_module_constants(PyObject *m);
#endif /* BTRFSUTILPY_H */
diff --git a/libbtrfsutil/python/filesystem.c b/libbtrfsutil/python/filesystem.c
new file mode 100644
index 00000000..627ed193
--- /dev/null
+++ b/libbtrfsutil/python/filesystem.c
@@ -0,0 +1,94 @@
+/*
+ * 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 *filesystem_sync(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&:sync", keywords,
+ &path_converter, &path))
+ return NULL;
+
+ if (path.path)
+ err = btrfs_util_sync(path.path);
+ else
+ err = btrfs_util_sync_fd(path.fd);
+ if (err) {
+ SetFromBtrfsUtilErrorWithPath(err, &path);
+ path_cleanup(&path);
+ return NULL;
+ }
+
+ path_cleanup(&path);
+ Py_RETURN_NONE;
+}
+
+PyObject *start_sync(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *keywords[] = {"path", NULL};
+ struct path_arg path = {.allow_fd = true};
+ uint64_t transid;
+ enum btrfs_util_error err;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:start_sync", keywords,
+ &path_converter, &path))
+ return NULL;
+
+ if (path.path)
+ err = btrfs_util_start_sync(path.path, &transid);
+ else
+ err = btrfs_util_start_sync_fd(path.fd, &transid);
+ if (err) {
+ SetFromBtrfsUtilErrorWithPath(err, &path);
+ path_cleanup(&path);
+ return NULL;
+ }
+
+ path_cleanup(&path);
+ return PyLong_FromUnsignedLongLong(transid);
+}
+
+PyObject *wait_sync(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ static char *keywords[] = {"path", "transid", NULL};
+ struct path_arg path = {.allow_fd = true};
+ unsigned long long transid = 0;
+ enum btrfs_util_error err;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|K:wait_sync", keywords,
+ &path_converter, &path, &transid))
+ return NULL;
+
+ if (path.path)
+ err = btrfs_util_wait_sync(path.path, transid);
+ else
+ err = btrfs_util_wait_sync_fd(path.fd, transid);
+ if (err) {
+ SetFromBtrfsUtilErrorWithPath(err, &path);
+ path_cleanup(&path);
+ return NULL;
+ }
+
+ path_cleanup(&path);
+ Py_RETURN_NONE;
+}
diff --git a/libbtrfsutil/python/module.c b/libbtrfsutil/python/module.c
index 24d962dc..9c1a864a 100644
--- a/libbtrfsutil/python/module.c
+++ b/libbtrfsutil/python/module.c
@@ -132,6 +132,27 @@ void path_cleanup(struct path_arg *path)
}
static PyMethodDef btrfsutil_methods[] = {
+ {"sync", (PyCFunction)filesystem_sync,
+ METH_VARARGS | METH_KEYWORDS,
+ "sync(path)\n\n"
+ "Sync a specific Btrfs filesystem.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor"},
+ {"start_sync", (PyCFunction)start_sync,
+ METH_VARARGS | METH_KEYWORDS,
+ "start_sync(path) -> int\n\n"
+ "Start a sync on a specific Btrfs filesystem and return the\n"
+ "transaction ID.\n\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor"},
+ {"wait_sync", (PyCFunction)wait_sync,
+ METH_VARARGS | METH_KEYWORDS,
+ "wait_sync(path, transid=0)\n\n"
+ "Wait for a transaction to sync.\n"
+ "Arguments:\n"
+ "path -- string, bytes, path-like object, or open file descriptor\n"
+ "transid -- int transaction ID to wait for, or zero for the current\n"
+ "transaction"},
{},
};
diff --git a/libbtrfsutil/python/setup.py b/libbtrfsutil/python/setup.py
index 478510ce..df44809f 100755
--- a/libbtrfsutil/python/setup.py
+++ b/libbtrfsutil/python/setup.py
@@ -90,6 +90,7 @@ module = Extension(
sources=[
'constants.c',
'error.c',
+ 'filesystem.c',
'module.c',
'qgroup.c',
],
diff --git a/libbtrfsutil/python/tests/test_filesystem.py b/libbtrfsutil/python/tests/test_filesystem.py
new file mode 100644
index 00000000..006a6b1e
--- /dev/null
+++ b/libbtrfsutil/python/tests/test_filesystem.py
@@ -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/>.
+
+import os
+import time
+
+import btrfsutil
+from tests import BtrfsTestCase, HAVE_PATH_LIKE
+
+
+def touch(path):
+ now = time.time()
+ os.utime(path, (now, now))
+
+
+class TestSubvolume(BtrfsTestCase):
+ def super_generation(self):
+ with open(self.image, 'rb') as f:
+ # csum is 32 bytes, fsid is 16 bytes, bytenr is 8 bytes, flags is 8
+ # bytes
+ f.seek(65536 + 32 + 16 + 8 + 8)
+ self.assertEqual(f.read(8), b'_BHRfS_M')
+ return int.from_bytes(f.read(8), 'little')
+
+ def test_sync(self):
+ old_generation = self.super_generation()
+ for arg in self.path_or_fd(self.mountpoint):
+ with self.subTest(type=type(arg)):
+ touch(arg)
+ btrfsutil.sync(arg)
+ new_generation = self.super_generation()
+ self.assertGreater(new_generation, old_generation)
+ old_generation = new_generation
+
+ def test_start_sync(self):
+ old_generation = self.super_generation()
+ for arg in self.path_or_fd(self.mountpoint):
+ with self.subTest(type=type(arg)):
+ touch(arg)
+ transid = btrfsutil.start_sync(arg)
+ self.assertGreater(transid, old_generation)
+
+ def test_wait_sync(self):
+ old_generation = self.super_generation()
+ for arg in self.path_or_fd(self.mountpoint):
+ with self.subTest(type=type(arg)):
+ touch(arg)
+ transid = btrfsutil.start_sync(arg)
+ btrfsutil.wait_sync(arg, transid)
+ new_generation = self.super_generation()
+ self.assertGreater(new_generation, old_generation)
+ old_generation = new_generation
+
+ touch(arg)
+ btrfsutil.start_sync(arg)
+ btrfsutil.wait_sync(arg)
+ new_generation = self.super_generation()
+ self.assertGreater(new_generation, old_generation)
+ old_generation = new_generation