Commit 2c043d29 authored by Kirill Smelkov's avatar Kirill Smelkov

X More effort to unmount failed wcfs.go

Else after first failing tests all furhter test can't start because
trying to stat testmntpt/.wcfs gives ENOTCONN.
parent ab962714
...@@ -96,8 +96,8 @@ LINKC = $(LINK.c) $< $(LOADLIBES) $(LDLIBS) -o $@ ...@@ -96,8 +96,8 @@ LINKC = $(LINK.c) $< $(LOADLIBES) $(LDLIBS) -o $@
# tests without instrumentation # tests without instrumentation
test.t : $(TESTS:%=%.trun) test.t : $(TESTS:%=%.trun)
%.trun : %.t %.trun : %.t
gdb -q -ex run -ex backtrace -ex quit $(XRUN<) #gdb -q -ex run -ex backtrace -ex quit $(XRUN<)
#$(XRUN<) $(XRUN<)
%.t : %.c $(ccan_config) %.t : %.c $(ccan_config)
$(LINKC) $(LINKC)
......
...@@ -209,7 +209,7 @@ def _start(zurl, *optv): # -> Conn ...@@ -209,7 +209,7 @@ def _start(zurl, *optv): # -> Conn
while 1: while 1:
ret = proc.poll() ret = proc.poll()
if ret is not None: if ret is not None:
raise "exited with %s" % ret raise RuntimeError("exited with %s" % ret)
_, _rx = select( _, _rx = select(
ctx.done().recv, # 0 ctx.done().recv, # 0
......
...@@ -2389,7 +2389,7 @@ func _main() (err error) { ...@@ -2389,7 +2389,7 @@ func _main() (err error) {
if kinit.Flags & fuse.CAP_EXPLICIT_INVAL_DATA == 0 { if kinit.Flags & fuse.CAP_EXPLICIT_INVAL_DATA == 0 {
w1 := fmt.Sprintf("%s does not support explicit data cache invalidation", kfuse) w1 := fmt.Sprintf("%s does not support explicit data cache invalidation", kfuse)
w2 := "-> performance will be AWFUL." w2 := "-> performance will be AWFUL."
w3 := "-> you need kernel which includes git.kernel.org/linus/ad2ba64dd489 ." w3 := "-> you need kernel which includes git.kernel.org/linus/ad2ba64dd489."
log.Error(w1); log.Error(w2); log.Error(w3) log.Error(w1); log.Error(w2); log.Error(w3)
fmt.Fprintf(os.Stderr, "W: wcfs: %s\nW: wcfs: %s\nW: wcfs: %s\n", w1, w2, w3) fmt.Fprintf(os.Stderr, "W: wcfs: %s\nW: wcfs: %s\nW: wcfs: %s\n", w1, w2, w3)
} }
......
...@@ -36,7 +36,8 @@ from ZODB.utils import z64, u64, p64 ...@@ -36,7 +36,8 @@ from ZODB.utils import z64, u64, p64
import sys, os, os.path, subprocess, threading, inspect, traceback, re import sys, os, os.path, subprocess, threading, inspect, traceback, re
from thread import get_ident as gettid from thread import get_ident as gettid
from time import gmtime from time import gmtime
from errno import EINVAL from errno import EINVAL, ENOENT, ENOTCONN
from stat import S_ISDIR
from signal import SIGQUIT, SIGKILL from signal import SIGQUIT, SIGKILL
from golang import go, chan, select, func, defer, default from golang import go, chan, select, func, defer, default
from golang import context, sync, time from golang import context, sync, time
...@@ -87,7 +88,7 @@ def setup_function(f): ...@@ -87,7 +88,7 @@ def setup_function(f):
# make sure we unmount wcfs after every test. # make sure we unmount wcfs after every test.
# (tDB checks this in more detail, but join tests don't use tDB) # (tDB checks this in more detail, but join tests don't use tDB)
def teardown_function(f): def teardown_function(f):
mounted = (0 == subprocess.call(["mountpoint", "-q", testmntpt])) mounted = is_mountpoint(testmntpt)
if mounted: if mounted:
subprocess.check_call(["fusermount", "-u", testmntpt]) subprocess.check_call(["fusermount", "-u", testmntpt])
if os.path.exists(testmntpt): if os.path.exists(testmntpt):
...@@ -195,12 +196,19 @@ class DFile: ...@@ -195,12 +196,19 @@ class DFile:
# #
# XXX print -> t.trace/debug() + t.verbose depending on py.test -v -v ? # XXX print -> t.trace/debug() + t.verbose depending on py.test -v -v ?
class tDB: class tDB:
@func
def __init__(t): def __init__(t):
t.root = testdb.dbopen() t.root = testdb.dbopen()
def _(): # close/unlock db if __init__ fails
exc = sys.exc_info()[1]
if exc is not None:
dbclose(t.root)
defer(_)
assert not os.path.exists(testmntpt) assert not os.path.exists(testmntpt)
t.wc = wcfs.join(testzurl, autostart=True) t.wc = wcfs.join(testzurl, autostart=True)
assert os.path.exists(testmntpt) assert os.path.exists(testmntpt)
assert 0 == subprocess.call(["mountpoint", "-q", testmntpt]) assert is_mountpoint(testmntpt)
# force-unmount wcfs on timeout to unstuck current test and let it fail. # force-unmount wcfs on timeout to unstuck current test and let it fail.
# Force-unmount can be done reliably only by writing into # Force-unmount can be done reliably only by writing into
...@@ -272,32 +280,33 @@ class tDB: ...@@ -272,32 +280,33 @@ class tDB:
# unmount and wait for wcfs to exit # unmount and wait for wcfs to exit
def _(): def _():
assert 0 != subprocess.call(["mountpoint", "-q", testmntpt]) assert not is_mountpoint(testmntpt)
os.rmdir(testmntpt) os.rmdir(testmntpt)
defer(_) defer(_)
def _(): def _():
# kill wcfs.go in case it is deadlocked and does not exit by itself # kill wcfs.go in case it is deadlocked and does not exit by itself
if procwait_(timeout(), t.wc._proc): if procwait_(timeout(), t.wc._proc):
return return
print("\nC: wcfs.go does not exit") print("\nC: wcfs.go does not exit", file=sys.stderr)
print("-> kill -QUIT wcfs.go ...\n") print("-> kill -QUIT wcfs.go ...\n", file=sys.stderr)
os.kill(t.wc._proc.pid, SIGQUIT) os.kill(t.wc._proc.pid, SIGQUIT)
if procwait_(timeout(), t.wc._proc): if procwait_(timeout(), t.wc._proc):
return return
print("\nC: wcfs.go does not exit (after SIGQUIT)") print("\nC: wcfs.go does not exit (after SIGQUIT)", file=sys.stderr)
print("-> kill -KILL wcfs.go ...\n") print("-> kill -KILL wcfs.go ...\n", file=sys.stderr)
os.kill(t.wc._proc.pid, SIGKILL) os.kill(t.wc._proc.pid, SIGKILL)
if procwait_(timeout(), t.wc._proc): if procwait_(timeout(), t.wc._proc):
return return
print("\nC: wcfs.go does not exit (after SIGKILL; probably it is stuck in kernel)") print("\nC: wcfs.go does not exit (after SIGKILL; probably it is stuck in kernel)", file=sys.stderr)
print("-> nothing we can do...\n") # XXX dump /proc/pid/task/*/stack instead (ignore EPERM) print("-> nothing we can do...\n", file=sys.stderr) # XXX dump /proc/pid/task/*/stack instead (ignore EPERM)
fail("wcfs.go does not exit even after SIGKILL") fail("wcfs.go does not exit even after SIGKILL")
defer(_) defer(_)
def _(): def _():
if not ready(t._wcfuseaborted): #if not ready(t._wcfuseaborted):
assert 0 == subprocess.call(["mountpoint", "-q", testmntpt]) # assert 0 == subprocess.call(["mountpoint", "-q", testmntpt])
assert is_mountpoint(testmntpt)
subprocess.check_call(["fusermount", "-u", testmntpt]) subprocess.check_call(["fusermount", "-u", testmntpt])
defer(_) defer(_)
...@@ -2057,6 +2066,27 @@ def procwait_(ctx, proc): # -> ok ...@@ -2057,6 +2066,27 @@ def procwait_(ctx, proc): # -> ok
raise raise
return True return True
# is_mountpoint returns whether path is a mountpoint
def is_mountpoint(path): # -> bool
# NOTE we don't call mountpoint directly on path, because if FUSE
# fileserver failed, the mountpoint will also fail and print ENOTCONN
try:
_ = os.lstat(path)
except OSError as e:
if e.errno == ENOENT:
return False
# "Transport endpoint is not connected" -> it is a failed FUSE server
# (XXX we can also grep /proc/mounts)
if e.errno == ENOTCONN:
return True
raise
if not S_ISDIR(_.st_mode):
return False
mounted = (0 == subprocess.call(["mountpoint", "-q", path]))
return mounted
# xdefer is like defer, but makes sure exception raised before deferred # xdefer is like defer, but makes sure exception raised before deferred
# function is called is not lost. # function is called is not lost.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment