Browse code

Fix some missing synchronization in libcontainerd

Signed-off-by: Brian Goff <cpuguy83@gmail.com>

Brian Goff authored on 2017/12/16 01:32:08
Showing 1 changed files
... ...
@@ -43,7 +43,7 @@ import (
43 43
 const InitProcessName = "init"
44 44
 
45 45
 type container struct {
46
-	sync.Mutex
46
+	mu sync.Mutex
47 47
 
48 48
 	bundleDir string
49 49
 	ctr       containerd.Container
... ...
@@ -52,6 +52,54 @@ type container struct {
52 52
 	oomKilled bool
53 53
 }
54 54
 
55
+func (c *container) setTask(t containerd.Task) {
56
+	c.mu.Lock()
57
+	c.task = t
58
+	c.mu.Unlock()
59
+}
60
+
61
+func (c *container) getTask() containerd.Task {
62
+	c.mu.Lock()
63
+	t := c.task
64
+	c.mu.Unlock()
65
+	return t
66
+}
67
+
68
+func (c *container) addProcess(id string, p containerd.Process) {
69
+	c.mu.Lock()
70
+	if c.execs == nil {
71
+		c.execs = make(map[string]containerd.Process)
72
+	}
73
+	c.execs[id] = p
74
+	c.mu.Unlock()
75
+}
76
+
77
+func (c *container) deleteProcess(id string) {
78
+	c.mu.Lock()
79
+	delete(c.execs, id)
80
+	c.mu.Unlock()
81
+}
82
+
83
+func (c *container) getProcess(id string) containerd.Process {
84
+	c.mu.Lock()
85
+	p := c.execs[id]
86
+	c.mu.Unlock()
87
+	return p
88
+}
89
+
90
+func (c *container) setOOMKilled(killed bool) {
91
+	c.mu.Lock()
92
+	c.oomKilled = killed
93
+	c.mu.Unlock()
94
+}
95
+
96
+func (c *container) getOOMKilled() bool {
97
+	c.mu.Lock()
98
+	killed := c.oomKilled
99
+	c.mu.Unlock()
100
+	return killed
101
+}
102
+
55 103
 type client struct {
56 104
 	sync.RWMutex // protects containers map
57 105
 
... ...
@@ -161,10 +209,10 @@ func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, run
161 161
 // Start create and start a task for the specified containerd id
162 162
 func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin bool, attachStdio StdioCallback) (int, error) {
163 163
 	ctr := c.getContainer(id)
164
-	switch {
165
-	case ctr == nil:
164
+	if ctr == nil {
166 165
 		return -1, errors.WithStack(newNotFoundError("no such container"))
167
-	case ctr.task != nil:
166
+	}
167
+	if t := ctr.getTask(); t != nil {
168 168
 		return -1, errors.WithStack(newConflictError("container already started"))
169 169
 	}
170 170
 
... ...
@@ -228,9 +276,7 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
228 228
 		return -1, err
229 229
 	}
230 230
 
231
-	c.Lock()
232
-	c.containers[id].task = t
233
-	c.Unlock()
231
+	ctr.setTask(t)
234 232
 
235 233
 	// Signal c.createIO that it can call CloseIO
236 234
 	close(stdinCloseSync)
... ...
@@ -240,9 +286,7 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
240 240
 			c.logger.WithError(err).WithField("container", id).
241 241
 				Error("failed to delete task after fail start")
242 242
 		}
243
-		c.Lock()
244
-		c.containers[id].task = nil
245
-		c.Unlock()
243
+		ctr.setTask(nil)
246 244
 		return -1, err
247 245
 	}
248 246
 
... ...
@@ -251,12 +295,15 @@ func (c *client) Start(ctx context.Context, id, checkpointDir string, withStdin
251 251
 
252 252
 func (c *client) Exec(ctx context.Context, containerID, processID string, spec *specs.Process, withStdin bool, attachStdio StdioCallback) (int, error) {
253 253
 	ctr := c.getContainer(containerID)
254
-	switch {
255
-	case ctr == nil:
254
+	if ctr == nil {
256 255
 		return -1, errors.WithStack(newNotFoundError("no such container"))
257
-	case ctr.task == nil:
256
+	}
257
+	t := ctr.getTask()
258
+	if t == nil {
258 259
 		return -1, errors.WithStack(newInvalidParameterError("container is not running"))
259
-	case ctr.execs != nil && ctr.execs[processID] != nil:
260
+	}
261
+
262
+	if p := ctr.getProcess(processID); p != nil {
260 263
 		return -1, errors.WithStack(newConflictError("id already in use"))
261 264
 	}
262 265
 
... ...
@@ -279,7 +326,7 @@ func (c *client) Exec(ctx context.Context, containerID, processID string, spec *
279 279
 		}
280 280
 	}()
281 281
 
282
-	p, err = ctr.task.Exec(ctx, processID, spec, func(id string) (cio.IO, error) {
282
+	p, err = t.Exec(ctx, processID, spec, func(id string) (cio.IO, error) {
283 283
 		rio, err = c.createIO(fifos, containerID, processID, stdinCloseSync, attachStdio)
284 284
 		return rio, err
285 285
 	})
... ...
@@ -292,21 +339,14 @@ func (c *client) Exec(ctx context.Context, containerID, processID string, spec *
292 292
 		return -1, err
293 293
 	}
294 294
 
295
-	ctr.Lock()
296
-	if ctr.execs == nil {
297
-		ctr.execs = make(map[string]containerd.Process)
298
-	}
299
-	ctr.execs[processID] = p
300
-	ctr.Unlock()
295
+	ctr.addProcess(processID, p)
301 296
 
302 297
 	// Signal c.createIO that it can call CloseIO
303 298
 	close(stdinCloseSync)
304 299
 
305 300
 	if err = p.Start(ctx); err != nil {
306 301
 		p.Delete(context.Background())
307
-		ctr.Lock()
308
-		delete(ctr.execs, processID)
309
-		ctr.Unlock()
302
+		ctr.deleteProcess(processID)
310 303
 		return -1, err
311 304
 	}
312 305
 
... ...
@@ -432,12 +472,9 @@ func (c *client) DeleteTask(ctx context.Context, containerID string) (uint32, ti
432 432
 		return 255, time.Now(), nil
433 433
 	}
434 434
 
435
-	c.Lock()
436
-	if ctr, ok := c.containers[containerID]; ok {
437
-		ctr.task = nil
435
+	if ctr := c.getContainer(containerID); ctr != nil {
436
+		ctr.setTask(nil)
438 437
 	}
439
-	c.Unlock()
440
-
441 438
 	return status.ExitCode(), status.ExitTime(), nil
442 439
 }
443 440
 
... ...
@@ -471,7 +508,12 @@ func (c *client) Status(ctx context.Context, containerID string) (Status, error)
471 471
 		return StatusUnknown, errors.WithStack(newNotFoundError("no such container"))
472 472
 	}
473 473
 
474
-	s, err := ctr.task.Status(ctx)
474
+	t := ctr.getTask()
475
+	if t == nil {
476
+		return StatusUnknown, errors.WithStack(newNotFoundError("no such task"))
477
+	}
478
+
479
+	s, err := t.Status(ctx)
475 480
 	if err != nil {
476 481
 		return StatusUnknown, err
477 482
 	}
... ...
@@ -547,26 +589,22 @@ func (c *client) removeContainer(id string) {
547 547
 
548 548
 func (c *client) getProcess(containerID, processID string) (containerd.Process, error) {
549 549
 	ctr := c.getContainer(containerID)
550
-	switch {
551
-	case ctr == nil:
550
+	if ctr == nil {
552 551
 		return nil, errors.WithStack(newNotFoundError("no such container"))
553
-	case ctr.task == nil:
552
+	}
553
+
554
+	t := ctr.getTask()
555
+	if t == nil {
554 556
 		return nil, errors.WithStack(newNotFoundError("container is not running"))
555
-	case processID == InitProcessName:
556
-		return ctr.task, nil
557
-	default:
558
-		ctr.Lock()
559
-		defer ctr.Unlock()
560
-		if ctr.execs == nil {
561
-			return nil, errors.WithStack(newNotFoundError("no execs"))
562
-		}
557
+	}
558
+	if processID == InitProcessName {
559
+		return t, nil
563 560
 	}
564 561
 
565
-	p := ctr.execs[processID]
562
+	p := ctr.getProcess(processID)
566 563
 	if p == nil {
567 564
 		return nil, errors.WithStack(newNotFoundError("no such exec"))
568 565
 	}
569
-
570 566
 	return p, nil
571 567
 }
572 568
 
... ...
@@ -624,12 +662,7 @@ func (c *client) processEvent(ctr *container, et EventType, ei EventInfo) {
624 624
 		}
625 625
 
626 626
 		if et == EventExit && ei.ProcessID != ei.ContainerID {
627
-			var p containerd.Process
628
-			ctr.Lock()
629
-			if ctr.execs != nil {
630
-				p = ctr.execs[ei.ProcessID]
631
-			}
632
-			ctr.Unlock()
627
+			p := ctr.getProcess(ei.ProcessID)
633 628
 			if p == nil {
634 629
 				c.logger.WithError(errors.New("no such process")).
635 630
 					WithFields(logrus.Fields{
... ...
@@ -645,9 +678,8 @@ func (c *client) processEvent(ctr *container, et EventType, ei EventInfo) {
645 645
 					"process":   ei.ProcessID,
646 646
 				}).Warn("failed to delete process")
647 647
 			}
648
-			c.Lock()
649
-			delete(ctr.execs, ei.ProcessID)
650
-			c.Unlock()
648
+			ctr.deleteProcess(ei.ProcessID)
649
+
651 650
 			ctr := c.getContainer(ei.ContainerID)
652 651
 			if ctr == nil {
653 652
 				c.logger.WithFields(logrus.Fields{
... ...
@@ -784,10 +816,10 @@ func (c *client) processEventStream(ctx context.Context) {
784 784
 		}
785 785
 
786 786
 		if oomKilled {
787
-			ctr.oomKilled = true
787
+			ctr.setOOMKilled(true)
788 788
 			oomKilled = false
789 789
 		}
790
-		ei.OOMKilled = ctr.oomKilled
790
+		ei.OOMKilled = ctr.getOOMKilled()
791 791
 
792 792
 		c.processEvent(ctr, et, ei)
793 793
 	}