Browse Source

Fix race in os sandbox sharing

There is a race in os sandbox sharing code where two containers which
are sharing the os sandbox try to recreate the os sandbox again which
might result in destroying the os sandbox and recreating it. Since the
os sandbox sharing is happening only for default sandbox, refactored the
code to create os sandbox only once inside a `sync.Once` api so that it
happens exactly once and gets reused by other containers. Also disabled
deleting this os sandbox.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
Jana Radhakrishnan 9 years ago
parent
commit
967917c8b4
2 changed files with 17 additions and 9 deletions
  1. 16 8
      libnetwork/controller.go
  2. 1 1
      libnetwork/sandbox.go

+ 16 - 8
libnetwork/controller.go

@@ -144,6 +144,8 @@ type controller struct {
 	unWatchCh      chan *endpoint
 	unWatchCh      chan *endpoint
 	svcDb          map[string]svcMap
 	svcDb          map[string]svcMap
 	nmap           map[string]*netWatch
 	nmap           map[string]*netWatch
+	defOsSbox      osl.Sandbox
+	sboxOnce       sync.Once
 	sync.Mutex
 	sync.Mutex
 }
 }
 
 
@@ -492,12 +494,6 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S
 		config:      containerConfig{},
 		config:      containerConfig{},
 		controller:  c,
 		controller:  c,
 	}
 	}
-	// This sandbox may be using an existing osl sandbox, sharing it with another sandbox
-	var peerSb Sandbox
-	c.WalkSandboxes(SandboxKeyWalker(&peerSb, sb.Key()))
-	if peerSb != nil {
-		sb.osSbox = peerSb.(*sandbox).osSbox
-	}
 
 
 	heap.Init(&sb.endpoints)
 	heap.Init(&sb.endpoints)
 
 
@@ -507,14 +503,26 @@ func (c *controller) NewSandbox(containerID string, options ...SandboxOption) (S
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	c.Lock()
+	if sb.config.useDefaultSandBox {
+		c.sboxOnce.Do(func() {
+			c.defOsSbox, err = osl.NewSandbox(sb.Key(), false)
+		})
+
+		if err != nil {
+			c.sboxOnce = sync.Once{}
+			return nil, fmt.Errorf("failed to create default sandbox: %v", err)
+		}
+
+		sb.osSbox = c.defOsSbox
+	}
+
 	if sb.osSbox == nil && !sb.config.useExternalKey {
 	if sb.osSbox == nil && !sb.config.useExternalKey {
 		if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox); err != nil {
 		if sb.osSbox, err = osl.NewSandbox(sb.Key(), !sb.config.useDefaultSandBox); err != nil {
-			c.Unlock()
 			return nil, fmt.Errorf("failed to create new osl sandbox: %v", err)
 			return nil, fmt.Errorf("failed to create new osl sandbox: %v", err)
 		}
 		}
 	}
 	}
 
 
+	c.Lock()
 	c.sandboxes[sb.id] = sb
 	c.sandboxes[sb.id] = sb
 	c.Unlock()
 	c.Unlock()
 	defer func() {
 	defer func() {

+ 1 - 1
libnetwork/sandbox.go

@@ -197,7 +197,7 @@ func (sb *sandbox) Delete() error {
 	// likely not required any more. Drop it.
 	// likely not required any more. Drop it.
 	etchosts.Drop(sb.config.hostsPath)
 	etchosts.Drop(sb.config.hostsPath)
 
 
-	if sb.osSbox != nil {
+	if sb.osSbox != nil && !sb.config.useDefaultSandBox {
 		sb.osSbox.Destroy()
 		sb.osSbox.Destroy()
 	}
 	}