Commit 15389db0 authored by Kirill Smelkov's avatar Kirill Smelkov

X wcfs: Tune _fuse_unmount to include `fusermount -u` error message into raised exception

Previously that message was printed to stderr and it was very confusing:
we had something in the exception message, something in the log and
something in stderr.

Now exception message is self-sufficient and log provides more details.
parent 6b22f8c4
......@@ -517,12 +517,11 @@ def _mkdir_p(path, mode=0o777): # -> created(bool)
# _fuse_unmount calls `fusermount -u` + logs details if unmount failed.
@func
def _fuse_unmount(mntpt):
ret = _sysproccall(["fusermount", "-u", mntpt], close_fds=True)
ret, out = _sysproccallout(["fusermount", "-u", mntpt])
if ret != 0:
# unmount failed, usually due to "device is busy".
# Log which files are still opened and reraise
def _():
log.warn("fuse_unmount %s failed", mntpt)
log.warn("# lsof %s" % mntpt)
# -w to avoid lots of
# lsof: WARNING: can't stat() fuse.wcfs file system /tmp/wcfs/X
......@@ -530,14 +529,16 @@ def _fuse_unmount(mntpt):
# if there are other uncleaned wcfs mountpoints.
# (lsof stats all filesystems on startup)
# XXX -> better use `fuser -m <mntpt>` (it says it will limit search to files only under mntpt) ?
lsof = _sysproc(["lsof", "-w", "+D", mntpt],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, _ = lsof.communicate()
ret, out = _sysproccallout(["lsof", "-w", "+D", mntpt])
log.warn(out)
if lsof.returncode:
if ret:
log.warn("(lsof failed)")
defer(_)
raise RuntimeError("fuse_unmount %s failed (logged details)" % mntpt)
out = out.rstrip() # kill trailing \n\n
emsg = "fuse_unmount %s: failed: %s" % (mntpt, out)
log.warn(emsg)
raise RuntimeError("%s\n(more details logged)" % emsg)
# _is_mountpoint returns whether path is a mountpoint
def _is_mountpoint(path): # -> bool
......@@ -577,12 +578,18 @@ def _sysproc(argv, **kw): # -> subprocess.Popen
path += ':'
path += '/bin:/usr/bin'
env['PATH'] = path
return subprocess.Popen(argv, env=env, **kw)
return subprocess.Popen(argv, env=env, close_fds=True, **kw)
# _sysproccall is to _sysproc like subprocess.call is to subprocess.Popen.
# _sysproccall calls _sysproc and waits for spawned program to complete.
def _sysproccall(argv, **kw): # -> retcode
return _sysproc(argv, **kw).wait()
# _sysproccallout calls _sysproc, waits for spawned program to complete and returns combined out/err.
def _sysproccallout(argv, **kw): # -> retcode, output
proc = _sysproc(argv, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, **kw)
out, _ = proc.communicate()
return proc.returncode, out
# _procwait waits for a process (subprocess.Popen) to terminate.
def _procwait(ctx, proc):
......
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