Merge commit '780de81b36'

This commit is contained in:
Kent Overstreet 2019-11-28 15:08:27 -05:00
commit ffced87f08
7 changed files with 96 additions and 14 deletions

34
INSTALL
View File

@ -1,3 +1,4 @@
-- Getting started --
Dependencies: Dependencies:
@ -20,3 +21,36 @@ On debian, you can install these with
uuid-dev zlib1g-dev valgrind uuid-dev zlib1g-dev valgrind
Then, just make && make install Then, just make && make install
-- Experimental features --
Experimental fuse support is currently disabled by default. Fuse support is at
an early stage and may corrupt your filesystem, so it should only be used for
testing. To enable, you'll also need to add:
* libfuse3
On debian:
apt install -y libfuse3-dev
Then, make using the BCACHEFS_FUSE environment variable:
BCACHEFS_FUSE=1 make &&
-- Tests --
Some tests are available to validate the "bcachefs" binary. The tests depend
on python3 pytest.
On debian:
apt install -u python3-pytest
Then, you can run the tests via:
make check
Optionally, you may wish to run tests in parallel using python3-pytest-xdist:
cd tests; pytest-3 -n4

View File

@ -38,7 +38,11 @@ ifdef D
CFLAGS+=-DCONFIG_BCACHEFS_DEBUG=y CFLAGS+=-DCONFIG_BCACHEFS_DEBUG=y
endif endif
PKGCONFIG_LIBS="blkid uuid liburcu libsodium zlib liblz4 libzstd fuse3" PKGCONFIG_LIBS="blkid uuid liburcu libsodium zlib liblz4 libzstd"
ifdef BCACHEFS_FUSE
PKGCONFIG_LIBS+="fuse3"
CFLAGS+=-DBCACHEFS_FUSE
endif
PKGCONFIG_CFLAGS:=$(shell $(PKG_CONFIG) --cflags $(PKGCONFIG_LIBS)) PKGCONFIG_CFLAGS:=$(shell $(PKG_CONFIG) --cflags $(PKGCONFIG_LIBS))
ifeq (,$(PKGCONFIG_CFLAGS)) ifeq (,$(PKGCONFIG_CFLAGS))

View File

@ -203,8 +203,10 @@ int main(int argc, char *argv[])
if (!strcmp(cmd, "setattr")) if (!strcmp(cmd, "setattr"))
return cmd_setattr(argc, argv); return cmd_setattr(argc, argv);
#ifdef BCACHEFS_FUSE
if (!strcmp(cmd, "fusemount")) if (!strcmp(cmd, "fusemount"))
return cmd_fusemount(argc, argv); return cmd_fusemount(argc, argv);
#endif
if (!strcmp(cmd, "--help")) { if (!strcmp(cmd, "--help")) {
usage(); usage();

View File

@ -1,3 +1,5 @@
#ifdef BCACHEFS_FUSE
#include <errno.h> #include <errno.h>
#include <float.h> #include <float.h>
#include <getopt.h> #include <getopt.h>
@ -1262,3 +1264,5 @@ out:
return ret ? 1 : 0; return ret ? 1 : 0;
} }
#endif /* BCACHEFS_FUSE */

View File

@ -29,26 +29,32 @@ def test_segfault():
ret = util.run(helper, 'segfault') ret = util.run(helper, 'segfault')
assert ret.returncode == -signal.SIGSEGV assert ret.returncode == -signal.SIGSEGV
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
def test_check(): def test_check():
with pytest.raises(subprocess.CalledProcessError): with pytest.raises(subprocess.CalledProcessError):
ret = util.run(helper, 'abort', check=True) ret = util.run(helper, 'abort', check=True)
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
def test_leak(): def test_leak():
with pytest.raises(util.ValgrindFailedError): with pytest.raises(util.ValgrindFailedError):
ret = util.run(helper, 'leak', valgrind=True) ret = util.run(helper, 'leak', valgrind=True)
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
def test_undefined(): def test_undefined():
with pytest.raises(util.ValgrindFailedError): with pytest.raises(util.ValgrindFailedError):
ret = util.run(helper, 'undefined', valgrind=True) ret = util.run(helper, 'undefined', valgrind=True)
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
def test_undefined_branch(): def test_undefined_branch():
with pytest.raises(util.ValgrindFailedError): with pytest.raises(util.ValgrindFailedError):
ret = util.run(helper, 'undefined_branch', valgrind=True) ret = util.run(helper, 'undefined_branch', valgrind=True)
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
def test_read_after_free(): def test_read_after_free():
with pytest.raises(util.ValgrindFailedError): with pytest.raises(util.ValgrindFailedError):
ret = util.run(helper, 'read_after_free', valgrind=True) ret = util.run(helper, 'read_after_free', valgrind=True)
@pytest.mark.skipif(not util.ENABLE_VALGRIND, reason="no valgrind")
def test_write_after_free(): def test_write_after_free():
with pytest.raises(util.ValgrindFailedError): with pytest.raises(util.ValgrindFailedError):
ret = util.run(helper, 'write_after_free', valgrind=True) ret = util.run(helper, 'write_after_free', valgrind=True)

View File

@ -2,14 +2,25 @@
# #
# Tests of the fuse mount functionality. # Tests of the fuse mount functionality.
import pytest
import os import os
import util import util
pytestmark = pytest.mark.skipif(
not util.have_fuse(), reason="bcachefs not built with fuse support.")
def test_mount(bfuse): def test_mount(bfuse):
bfuse.mount() bfuse.mount()
bfuse.unmount() bfuse.unmount()
bfuse.verify() bfuse.verify()
def test_remount(bfuse):
bfuse.mount()
bfuse.unmount()
bfuse.mount()
bfuse.unmount()
bfuse.verify()
def test_lostfound(bfuse): def test_lostfound(bfuse):
bfuse.mount() bfuse.mount()

View File

@ -4,6 +4,7 @@ import os
import pytest import pytest
import re import re
import subprocess import subprocess
import sys
import tempfile import tempfile
import threading import threading
import time import time
@ -15,6 +16,8 @@ BCH_PATH = DIR / 'bcachefs'
VPAT = re.compile(r'ERROR SUMMARY: (\d+) errors from (\d+) contexts') VPAT = re.compile(r'ERROR SUMMARY: (\d+) errors from (\d+) contexts')
ENABLE_VALGRIND = os.getenv('BCACHEFS_TEST_USE_VALGRIND', 'yes') == 'yes'
class ValgrindFailedError(Exception): class ValgrindFailedError(Exception):
def __init__(self, log): def __init__(self, log):
self.log = log self.log = log
@ -36,6 +39,7 @@ def run(cmd, *args, valgrind=False, check=False):
ValgrindFailedError if there's a problem. ValgrindFailedError if there's a problem.
""" """
cmds = [cmd] + list(args) cmds = [cmd] + list(args)
valgrind = valgrind and ENABLE_VALGRIND
if valgrind: if valgrind:
vout = tempfile.NamedTemporaryFile() vout = tempfile.NamedTemporaryFile()
@ -123,7 +127,7 @@ class FuseError(Exception):
def __init__(self, msg): def __init__(self, msg):
self.msg = msg self.msg = msg
class BFuse(threading.Thread): class BFuse:
'''bcachefs fuse runner. '''bcachefs fuse runner.
This class runs bcachefs in fusemount mode, and waits until the mount has This class runs bcachefs in fusemount mode, and waits until the mount has
@ -133,7 +137,7 @@ class BFuse(threading.Thread):
''' '''
def __init__(self, dev, mnt): def __init__(self, dev, mnt):
threading.Thread.__init__(self) self.thread = None
self.dev = dev self.dev = dev
self.mnt = mnt self.mnt = mnt
self.ready = threading.Event() self.ready = threading.Event()
@ -146,11 +150,16 @@ class BFuse(threading.Thread):
def run(self): def run(self):
"""Background thread which runs "bcachefs fusemount" under valgrind""" """Background thread which runs "bcachefs fusemount" under valgrind"""
vout = None
cmd = []
if ENABLE_VALGRIND:
vout = tempfile.NamedTemporaryFile() vout = tempfile.NamedTemporaryFile()
cmd = [ 'valgrind', cmd += [ 'valgrind',
'--leak-check=full', '--leak-check=full',
'--log-file={}'.format(vout.name), '--log-file={}'.format(vout.name) ]
BCH_PATH,
cmd += [ BCH_PATH,
'fusemount', '-f', self.dev, self.mnt] 'fusemount', '-f', self.dev, self.mnt]
print("Running {}".format(cmd)) print("Running {}".format(cmd))
@ -188,7 +197,11 @@ class BFuse(threading.Thread):
def mount(self): def mount(self):
print("Starting fuse thread.") print("Starting fuse thread.")
self.start()
assert not self.thread
self.thread = threading.Thread(target=self.run)
self.thread.start()
self.ready.wait() self.ready.wait()
print("Fuse is mounted.") print("Fuse is mounted.")
@ -197,14 +210,22 @@ class BFuse(threading.Thread):
run("fusermount3", "-zu", self.mnt) run("fusermount3", "-zu", self.mnt)
print("Waiting for thread to exit.") print("Waiting for thread to exit.")
self.join(timeout) self.thread.join(timeout)
if self.isAlive(): if self.thread.is_alive():
self.proc.kill() self.proc.kill()
self.join() self.thread.join()
self.thread = None
self.ready.clear()
if self.vout:
check_valgrind(self.vout) check_valgrind(self.vout)
def verify(self): def verify(self):
assert self.returncode == 0 assert self.returncode == 0
assert len(self.stdout) > 0 assert len(self.stdout) > 0
assert len(self.stderr) == 0 assert len(self.stderr) == 0
def have_fuse():
res = run(BCH_PATH, 'fusemount', valgrind=False)
return "Please supply a mountpoint." in res.stdout