From 13b48f2e6a186321084fa8159e8cc2659ed221a2 Mon Sep 17 00:00:00 2001 From: Nicolas Lacasse Date: Wed, 7 Nov 2018 13:54:47 -0800 Subject: [PATCH] AsyncBarrier should be run after all defers in destroyContainerFS. destroyContainerFS must wait for all async operations to finish before returning. In an attempt to do this, we call fs.AsyncBarrier() at the end of the function. However, there are many defer'd DecRefs which end up running AFTER the AsyncBarrier() call. This CL fixes this by calling fs.AsyncBarrier() in the first defer statement, thus ensuring that it runs at the end of the function, after all other defers. PiperOrigin-RevId: 220523545 Change-Id: I5e96ee9ea6d86eeab788ff964484c50ef7f64a2f --- runsc/boot/fs.go | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/runsc/boot/fs.go b/runsc/boot/fs.go index e52c89fe4..3f3f9bef6 100644 --- a/runsc/boot/fs.go +++ b/runsc/boot/fs.go @@ -638,6 +638,19 @@ func setExecutablePath(ctx context.Context, mns *fs.MountNamespace, procArgs *ke // destroyContainerFS cleans up the filesystem by unmounting all mounts for the // given container and deleting the container root directory. func destroyContainerFS(ctx context.Context, cid string, k *kernel.Kernel) error { + defer func() { + // Flushing dirent references triggers many async close + // operations. We must wait for those to complete before + // returning, otherwise the caller may kill the gofer before + // they complete, causing a cascade of failing RPCs. + // + // This must take place in the first deferred function, so that + // it runs after all the other deferred DecRef() calls in this + // function. + log.Infof("Waiting for async filesystem operations to complete") + fs.AsyncBarrier() + }() + // First get a reference to the container root directory. mns := k.RootMountNamespace() mnsRoot := mns.Root() @@ -687,12 +700,5 @@ func destroyContainerFS(ctx context.Context, cid string, k *kernel.Kernel) error return fmt.Errorf("error removing directory %q: %v", containerRoot, err) } - // Flushing dirent references triggers many async close operations. We - // must wait for those to complete before returning, otherwise the - // caller may kill the gofer before they complete, causing a cascade of - // failing RPCs. - log.Infof("Waiting for async filesystem operations to complete") - fs.AsyncBarrier() - return nil }