I met a problem that container blocked by seteuid/setegid
which is call in lxcContainerSetID on UP system and libvirt
compiled with --with-fuse=yes.
I looked into the glibc's codes, and found setxid in glibc
calls futex() to wait for other threads to change their
setxid_futex to 0(see setxid_mark_thread in glibc).
since the process created by clone system call will not
share the memory with the other threads and the context
of memory doesn't changed until we call execl.(COW)
So if the process which created by clone is called before
fuse thread being stated, the new setxid_futex of fuse
thread will not be saw in this process, it will be blocked
forever.
Maybe this problem should be fixed in glibc, but I send
this patch as a quick fix.
Signed-off-by: Gao feng <gaofeng(a)cn.fujitsu.com>
---
src/lxc/lxc_controller.c | 13 ++++++++++++-
src/lxc/lxc_fuse.c | 6 +++++-
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/src/lxc/lxc_controller.c b/src/lxc/lxc_controller.c
index c8f68c0..ed83bb3 100644
--- a/src/lxc/lxc_controller.c
+++ b/src/lxc/lxc_controller.c
@@ -1977,7 +1977,18 @@ cleanup:
static int
virLXCControllerSetupFuse(virLXCControllerPtr ctrl)
{
- return lxcSetupFuse(&ctrl->fuse, ctrl->def);
+ int ret = lxcSetupFuse(&ctrl->fuse, ctrl->def);
+
+ if (!ret) {
+ /* Wait for fuse thread starting run, so we
+ * can make sure the setxid_futex of fuse thread
+ * is 0(see start_thread of glibc), otherwise
+ * the lxcContainerChild will block at setxid. */
+ virMutexLock(&ctrl->fuse->lock);
+ virMutexUnlock(&ctrl->fuse->lock);
+ }
+
+ return ret;
}
static int
diff --git a/src/lxc/lxc_fuse.c b/src/lxc/lxc_fuse.c
index 9d12832..8cddfa8 100644
--- a/src/lxc/lxc_fuse.c
+++ b/src/lxc/lxc_fuse.c
@@ -272,6 +272,8 @@ static void lxcFuseDestroy(virLXCFusePtr fuse)
static void lxcFuseRun(void *opaque)
{
virLXCFusePtr fuse = opaque;
+ /* Let libvirt_lxc continue. */
+ virMutexUnlock(&fuse->lock);
if (fuse_loop(fuse->fuse) < 0)
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -321,7 +323,9 @@ int lxcSetupFuse(virLXCFusePtr *f, virDomainDefPtr def)
fuse_unmount(fuse->mountpoint, fuse->ch);
goto cleanup1;
}
-
+ /* Get mutex lock, lxcFuseRun will unlock it. this will
+ * cause libvirt_lxc wait for the fuse thread starting. */
+ virMutexLock(&fuse->lock);
if (virThreadCreate(&fuse->thread, false, lxcFuseRun,
(void *)fuse) < 0) {
lxcFuseDestroy(fuse);
--
1.8.3.1