Browse code

wip: bump containerd and runc version

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>

Michael Crosby authored on 2018/11/10 03:11:04
Showing 18 changed files
... ...
@@ -4,7 +4,7 @@
4 4
 # containerd is also pinned in vendor.conf. When updating the binary
5 5
 # version you may also need to update the vendor version to pick up bug
6 6
 # fixes or new APIs.
7
-CONTAINERD_COMMIT=8afcade1a6041b8301b6f6d8b88bae909993b989 # v1.2.0-13-g8afcade1
7
+CONTAINERD_COMMIT=aa537a67b3a9026c423a63dbaf71e4cc0776b2ad # v1.2.0-13-g8afcade1
8 8
 
9 9
 install_containerd() {
10 10
 	echo "Install containerd version $CONTAINERD_COMMIT"
... ...
@@ -79,7 +79,7 @@ google.golang.org/grpc v1.12.0
79 79
 # the containerd project first, and update both after that is merged.
80 80
 # This commit does not need to match RUNC_COMMIT as it is used for helper
81 81
 # packages but should be newer or equal.
82
-github.com/opencontainers/runc 9f1e94488e5e478e084fef997f022565b64b01d9
82
+github.com/opencontainers/runc 10d38b660a77168360df3522881e2dc2be5056bd
83 83
 github.com/opencontainers/runtime-spec 5684b8af48c1ac3b1451fa499724e30e3c20a294 # v1.0.1-49-g5684b8a
84 84
 github.com/opencontainers/image-spec v1.0.1
85 85
 github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
... ...
@@ -118,7 +118,7 @@ github.com/googleapis/gax-go v2.0.0
118 118
 google.golang.org/genproto 694d95ba50e67b2e363f3483057db5d4910c18f9
119 119
 
120 120
 # containerd
121
-github.com/containerd/containerd c4446665cb9c30056f4998ed953e6d4ff22c7c39 # v1.2.0
121
+github.com/containerd/containerd aa537a67b3a9026c423a63dbaf71e4cc0776b2ad # v1.2.0
122 122
 github.com/containerd/fifo 3d5202aec260678c48179c56f40e6f38a095738c
123 123
 github.com/containerd/continuity bd77b46c8352f74eb12c85bdc01f4b90f69d66b4
124 124
 github.com/containerd/cgroups 5e610833b72089b37d0e615de9a92dfc043757c2
... ...
@@ -224,7 +224,8 @@ This will be the best place to discuss design and implementation.
224 224
 
225 225
 For sync communication we have a community slack with a #containerd channel that everyone is welcome to join and chat about development.
226 226
 
227
-**Slack:** https://join.slack.com/t/dockercommunity/shared_invite/enQtNDM4NjAwNDMyOTUwLWZlMDZmYWRjZjk4Zjc5ZGQ5NWZkOWI1Yjk2NGE3ZWVlYjYxM2VhYjczOWIyZDFhZTE3NTUwZWQzMjhmNGYyZTg
227
+**Slack:** Catch us in the #containerd and #containerd-dev channels on dockercommunity.slack.com.
228
+[Click here for an invite to docker community slack.](https://join.slack.com/t/dockercommunity/shared_invite/enQtNDY4MDc1Mzc0MzIwLTgxZDBlMmM4ZGEyNDc1N2FkMzlhODJkYmE1YTVkYjM1MDE3ZjAwZjBkOGFlOTJkZjRmZGYzNjYyY2M3ZTUxYzQ)
228 229
 
229 230
 ### Reporting security issues
230 231
 
... ...
@@ -249,3 +250,8 @@ Please find all these core project documents, including the:
249 249
  * and [Contributing guidelines](https://github.com/containerd/project/blob/master/CONTRIBUTING.md)
250 250
 
251 251
 information in our [`containerd/project`](https://github.com/containerd/project) repository.
252
+
253
+## Adoption
254
+
255
+Interested to see who is using containerd? Are you using containerd in a project?
256
+Please add yourself via pull request to our [ADOPTERS.md](./ADOPTERS.md) file.
... ...
@@ -75,7 +75,7 @@ type ResolverOptions struct {
75 75
 
76 76
 	// Credentials provides username and secret given a host.
77 77
 	// If username is empty but a secret is given, that secret
78
-	// is interpretted as a long lived token.
78
+	// is interpreted as a long lived token.
79 79
 	// Deprecated: use Authorizer
80 80
 	Credentials func(string) (string, string, error)
81 81
 
... ...
@@ -40,7 +40,6 @@ func (s Stdio) IsNull() bool {
40 40
 
41 41
 // Process on a system
42 42
 type Process interface {
43
-	State
44 43
 	// ID returns the id for the process
45 44
 	ID() string
46 45
 	// Pid returns the pid for the process
... ...
@@ -57,10 +56,6 @@ type Process interface {
57 57
 	Status(context.Context) (string, error)
58 58
 	// Wait blocks until the process has exited
59 59
 	Wait()
60
-}
61
-
62
-// State of a process
63
-type State interface {
64 60
 	// Resize resizes the process console
65 61
 	Resize(ws console.WinSize) error
66 62
 	// Start execution of the process
... ...
@@ -41,7 +41,7 @@ import (
41 41
 type execProcess struct {
42 42
 	wg sync.WaitGroup
43 43
 
44
-	proc.State
44
+	execState execState
45 45
 
46 46
 	mu      sync.Mutex
47 47
 	id      string
... ...
@@ -86,6 +86,13 @@ func (e *execProcess) ExitedAt() time.Time {
86 86
 	return e.exited
87 87
 }
88 88
 
89
+func (e *execProcess) SetExited(status int) {
90
+	e.mu.Lock()
91
+	defer e.mu.Unlock()
92
+
93
+	e.execState.SetExited(status)
94
+}
95
+
89 96
 func (e *execProcess) setExited(status int) {
90 97
 	e.status = status
91 98
 	e.exited = time.Now()
... ...
@@ -93,6 +100,13 @@ func (e *execProcess) setExited(status int) {
93 93
 	close(e.waitBlock)
94 94
 }
95 95
 
96
+func (e *execProcess) Delete(ctx context.Context) error {
97
+	e.mu.Lock()
98
+	defer e.mu.Unlock()
99
+
100
+	return e.execState.Delete(ctx)
101
+}
102
+
96 103
 func (e *execProcess) delete(ctx context.Context) error {
97 104
 	e.wg.Wait()
98 105
 	if e.io != nil {
... ...
@@ -107,6 +121,13 @@ func (e *execProcess) delete(ctx context.Context) error {
107 107
 	return nil
108 108
 }
109 109
 
110
+func (e *execProcess) Resize(ws console.WinSize) error {
111
+	e.mu.Lock()
112
+	defer e.mu.Unlock()
113
+
114
+	return e.execState.Resize(ws)
115
+}
116
+
110 117
 func (e *execProcess) resize(ws console.WinSize) error {
111 118
 	if e.console == nil {
112 119
 		return nil
... ...
@@ -114,6 +135,13 @@ func (e *execProcess) resize(ws console.WinSize) error {
114 114
 	return e.console.Resize(ws)
115 115
 }
116 116
 
117
+func (e *execProcess) Kill(ctx context.Context, sig uint32, _ bool) error {
118
+	e.mu.Lock()
119
+	defer e.mu.Unlock()
120
+
121
+	return e.execState.Kill(ctx, sig, false)
122
+}
123
+
117 124
 func (e *execProcess) kill(ctx context.Context, sig uint32, _ bool) error {
118 125
 	pid := e.pid
119 126
 	if pid != 0 {
... ...
@@ -132,6 +160,13 @@ func (e *execProcess) Stdio() proc.Stdio {
132 132
 	return e.stdio
133 133
 }
134 134
 
135
+func (e *execProcess) Start(ctx context.Context) error {
136
+	e.mu.Lock()
137
+	defer e.mu.Unlock()
138
+
139
+	return e.execState.Start(ctx)
140
+}
141
+
135 142
 func (e *execProcess) start(ctx context.Context) (err error) {
136 143
 	var (
137 144
 		socket  *runc.Socket
... ...
@@ -25,6 +25,14 @@ import (
25 25
 	"github.com/pkg/errors"
26 26
 )
27 27
 
28
+type execState interface {
29
+	Resize(console.WinSize) error
30
+	Start(context.Context) error
31
+	Delete(context.Context) error
32
+	Kill(context.Context, uint32, bool) error
33
+	SetExited(int)
34
+}
35
+
28 36
 type execCreatedState struct {
29 37
 	p *execProcess
30 38
 }
... ...
@@ -32,11 +40,11 @@ type execCreatedState struct {
32 32
 func (s *execCreatedState) transition(name string) error {
33 33
 	switch name {
34 34
 	case "running":
35
-		s.p.State = &execRunningState{p: s.p}
35
+		s.p.execState = &execRunningState{p: s.p}
36 36
 	case "stopped":
37
-		s.p.State = &execStoppedState{p: s.p}
37
+		s.p.execState = &execStoppedState{p: s.p}
38 38
 	case "deleted":
39
-		s.p.State = &deletedState{}
39
+		s.p.execState = &deletedState{}
40 40
 	default:
41 41
 		return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
42 42
 	}
... ...
@@ -44,15 +52,10 @@ func (s *execCreatedState) transition(name string) error {
44 44
 }
45 45
 
46 46
 func (s *execCreatedState) Resize(ws console.WinSize) error {
47
-	s.p.mu.Lock()
48
-	defer s.p.mu.Unlock()
49
-
50 47
 	return s.p.resize(ws)
51 48
 }
52 49
 
53 50
 func (s *execCreatedState) Start(ctx context.Context) error {
54
-	s.p.mu.Lock()
55
-	defer s.p.mu.Unlock()
56 51
 	if err := s.p.start(ctx); err != nil {
57 52
 		return err
58 53
 	}
... ...
@@ -63,22 +66,15 @@ func (s *execCreatedState) Delete(ctx context.Context) error {
63 63
 	if err := s.p.delete(ctx); err != nil {
64 64
 		return err
65 65
 	}
66
-	s.p.mu.Lock()
67
-	defer s.p.mu.Unlock()
66
+
68 67
 	return s.transition("deleted")
69 68
 }
70 69
 
71 70
 func (s *execCreatedState) Kill(ctx context.Context, sig uint32, all bool) error {
72
-	s.p.mu.Lock()
73
-	defer s.p.mu.Unlock()
74
-
75 71
 	return s.p.kill(ctx, sig, all)
76 72
 }
77 73
 
78 74
 func (s *execCreatedState) SetExited(status int) {
79
-	s.p.mu.Lock()
80
-	defer s.p.mu.Unlock()
81
-
82 75
 	s.p.setExited(status)
83 76
 
84 77
 	if err := s.transition("stopped"); err != nil {
... ...
@@ -93,7 +89,7 @@ type execRunningState struct {
93 93
 func (s *execRunningState) transition(name string) error {
94 94
 	switch name {
95 95
 	case "stopped":
96
-		s.p.State = &execStoppedState{p: s.p}
96
+		s.p.execState = &execStoppedState{p: s.p}
97 97
 	default:
98 98
 		return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
99 99
 	}
... ...
@@ -101,37 +97,22 @@ func (s *execRunningState) transition(name string) error {
101 101
 }
102 102
 
103 103
 func (s *execRunningState) Resize(ws console.WinSize) error {
104
-	s.p.mu.Lock()
105
-	defer s.p.mu.Unlock()
106
-
107 104
 	return s.p.resize(ws)
108 105
 }
109 106
 
110 107
 func (s *execRunningState) Start(ctx context.Context) error {
111
-	s.p.mu.Lock()
112
-	defer s.p.mu.Unlock()
113
-
114 108
 	return errors.Errorf("cannot start a running process")
115 109
 }
116 110
 
117 111
 func (s *execRunningState) Delete(ctx context.Context) error {
118
-	s.p.mu.Lock()
119
-	defer s.p.mu.Unlock()
120
-
121 112
 	return errors.Errorf("cannot delete a running process")
122 113
 }
123 114
 
124 115
 func (s *execRunningState) Kill(ctx context.Context, sig uint32, all bool) error {
125
-	s.p.mu.Lock()
126
-	defer s.p.mu.Unlock()
127
-
128 116
 	return s.p.kill(ctx, sig, all)
129 117
 }
130 118
 
131 119
 func (s *execRunningState) SetExited(status int) {
132
-	s.p.mu.Lock()
133
-	defer s.p.mu.Unlock()
134
-
135 120
 	s.p.setExited(status)
136 121
 
137 122
 	if err := s.transition("stopped"); err != nil {
... ...
@@ -146,7 +127,7 @@ type execStoppedState struct {
146 146
 func (s *execStoppedState) transition(name string) error {
147 147
 	switch name {
148 148
 	case "deleted":
149
-		s.p.State = &deletedState{}
149
+		s.p.execState = &deletedState{}
150 150
 	default:
151 151
 		return errors.Errorf("invalid state transition %q to %q", stateName(s), name)
152 152
 	}
... ...
@@ -154,16 +135,10 @@ func (s *execStoppedState) transition(name string) error {
154 154
 }
155 155
 
156 156
 func (s *execStoppedState) Resize(ws console.WinSize) error {
157
-	s.p.mu.Lock()
158
-	defer s.p.mu.Unlock()
159
-
160 157
 	return errors.Errorf("cannot resize a stopped container")
161 158
 }
162 159
 
163 160
 func (s *execStoppedState) Start(ctx context.Context) error {
164
-	s.p.mu.Lock()
165
-	defer s.p.mu.Unlock()
166
-
167 161
 	return errors.Errorf("cannot start a stopped process")
168 162
 }
169 163
 
... ...
@@ -171,15 +146,11 @@ func (s *execStoppedState) Delete(ctx context.Context) error {
171 171
 	if err := s.p.delete(ctx); err != nil {
172 172
 		return err
173 173
 	}
174
-	s.p.mu.Lock()
175
-	defer s.p.mu.Unlock()
174
+
176 175
 	return s.transition("deleted")
177 176
 }
178 177
 
179 178
 func (s *execStoppedState) Kill(ctx context.Context, sig uint32, all bool) error {
180
-	s.p.mu.Lock()
181
-	defer s.p.mu.Unlock()
182
-
183 179
 	return s.p.kill(ctx, sig, all)
184 180
 }
185 181
 
... ...
@@ -46,8 +46,8 @@ const InitPidFile = "init.pid"
46 46
 
47 47
 // Init represents an initial process for a container
48 48
 type Init struct {
49
-	wg sync.WaitGroup
50
-	initState
49
+	wg        sync.WaitGroup
50
+	initState initState
51 51
 
52 52
 	// mu is used to ensure that `Start()` and `Exited()` calls return in
53 53
 	// the right order when invoked in separate go routines.
... ...
@@ -212,6 +212,7 @@ func (p *Init) Pid() int {
212 212
 func (p *Init) ExitStatus() int {
213 213
 	p.mu.Lock()
214 214
 	defer p.mu.Unlock()
215
+
215 216
 	return p.status
216 217
 }
217 218
 
... ...
@@ -219,6 +220,7 @@ func (p *Init) ExitStatus() int {
219 219
 func (p *Init) ExitedAt() time.Time {
220 220
 	p.mu.Lock()
221 221
 	defer p.mu.Unlock()
222
+
222 223
 	return p.exited
223 224
 }
224 225
 
... ...
@@ -226,6 +228,7 @@ func (p *Init) ExitedAt() time.Time {
226 226
 func (p *Init) Status(ctx context.Context) (string, error) {
227 227
 	p.mu.Lock()
228 228
 	defer p.mu.Unlock()
229
+
229 230
 	c, err := p.runtime.State(ctx, p.id)
230 231
 	if err != nil {
231 232
 		if strings.Contains(err.Error(), "does not exist") {
... ...
@@ -236,11 +239,27 @@ func (p *Init) Status(ctx context.Context) (string, error) {
236 236
 	return c.Status, nil
237 237
 }
238 238
 
239
-func (p *Init) start(context context.Context) error {
240
-	err := p.runtime.Start(context, p.id)
239
+// Start the init process
240
+func (p *Init) Start(ctx context.Context) error {
241
+	p.mu.Lock()
242
+	defer p.mu.Unlock()
243
+
244
+	return p.initState.Start(ctx)
245
+}
246
+
247
+func (p *Init) start(ctx context.Context) error {
248
+	err := p.runtime.Start(ctx, p.id)
241 249
 	return p.runtimeError(err, "OCI runtime start failed")
242 250
 }
243 251
 
252
+// SetExited of the init process with the next status
253
+func (p *Init) SetExited(status int) {
254
+	p.mu.Lock()
255
+	defer p.mu.Unlock()
256
+
257
+	p.initState.SetExited(status)
258
+}
259
+
244 260
 func (p *Init) setExited(status int) {
245 261
 	p.exited = time.Now()
246 262
 	p.status = status
... ...
@@ -248,9 +267,17 @@ func (p *Init) setExited(status int) {
248 248
 	close(p.waitBlock)
249 249
 }
250 250
 
251
-func (p *Init) delete(context context.Context) error {
251
+// Delete the init process
252
+func (p *Init) Delete(ctx context.Context) error {
253
+	p.mu.Lock()
254
+	defer p.mu.Unlock()
255
+
256
+	return p.initState.Delete(ctx)
257
+}
258
+
259
+func (p *Init) delete(ctx context.Context) error {
252 260
 	p.wg.Wait()
253
-	err := p.runtime.Delete(context, p.id, nil)
261
+	err := p.runtime.Delete(ctx, p.id, nil)
254 262
 	// ignore errors if a runtime has already deleted the process
255 263
 	// but we still hold metadata and pipes
256 264
 	//
... ...
@@ -270,7 +297,7 @@ func (p *Init) delete(context context.Context) error {
270 270
 		p.io.Close()
271 271
 	}
272 272
 	if err2 := mount.UnmountAll(p.Rootfs, 0); err2 != nil {
273
-		log.G(context).WithError(err2).Warn("failed to cleanup rootfs mount")
273
+		log.G(ctx).WithError(err2).Warn("failed to cleanup rootfs mount")
274 274
 		if err == nil {
275 275
 			err = errors.Wrap(err2, "failed rootfs umount")
276 276
 		}
... ...
@@ -278,6 +305,17 @@ func (p *Init) delete(context context.Context) error {
278 278
 	return err
279 279
 }
280 280
 
281
+// Resize the init processes console
282
+func (p *Init) Resize(ws console.WinSize) error {
283
+	p.mu.Lock()
284
+	defer p.mu.Unlock()
285
+
286
+	if p.console == nil {
287
+		return nil
288
+	}
289
+	return p.console.Resize(ws)
290
+}
291
+
281 292
 func (p *Init) resize(ws console.WinSize) error {
282 293
 	if p.console == nil {
283 294
 		return nil
... ...
@@ -285,26 +323,40 @@ func (p *Init) resize(ws console.WinSize) error {
285 285
 	return p.console.Resize(ws)
286 286
 }
287 287
 
288
-func (p *Init) pause(context context.Context) error {
289
-	err := p.runtime.Pause(context, p.id)
290
-	return p.runtimeError(err, "OCI runtime pause failed")
288
+// Pause the init process and all its child processes
289
+func (p *Init) Pause(ctx context.Context) error {
290
+	p.mu.Lock()
291
+	defer p.mu.Unlock()
292
+
293
+	return p.initState.Pause(ctx)
291 294
 }
292 295
 
293
-func (p *Init) resume(context context.Context) error {
294
-	err := p.runtime.Resume(context, p.id)
295
-	return p.runtimeError(err, "OCI runtime resume failed")
296
+// Resume the init process and all its child processes
297
+func (p *Init) Resume(ctx context.Context) error {
298
+	p.mu.Lock()
299
+	defer p.mu.Unlock()
300
+
301
+	return p.initState.Resume(ctx)
296 302
 }
297 303
 
298
-func (p *Init) kill(context context.Context, signal uint32, all bool) error {
299
-	err := p.runtime.Kill(context, p.id, int(signal), &runc.KillOpts{
304
+// Kill the init process
305
+func (p *Init) Kill(ctx context.Context, signal uint32, all bool) error {
306
+	p.mu.Lock()
307
+	defer p.mu.Unlock()
308
+
309
+	return p.initState.Kill(ctx, signal, all)
310
+}
311
+
312
+func (p *Init) kill(ctx context.Context, signal uint32, all bool) error {
313
+	err := p.runtime.Kill(ctx, p.id, int(signal), &runc.KillOpts{
300 314
 		All: all,
301 315
 	})
302 316
 	return checkKillError(err)
303 317
 }
304 318
 
305 319
 // KillAll processes belonging to the init process
306
-func (p *Init) KillAll(context context.Context) error {
307
-	err := p.runtime.Kill(context, p.id, int(syscall.SIGKILL), &runc.KillOpts{
320
+func (p *Init) KillAll(ctx context.Context) error {
321
+	err := p.runtime.Kill(ctx, p.id, int(syscall.SIGKILL), &runc.KillOpts{
308 322
 		All: true,
309 323
 	})
310 324
 	return p.runtimeError(err, "OCI runtime killall failed")
... ...
@@ -320,8 +372,16 @@ func (p *Init) Runtime() *runc.Runc {
320 320
 	return p.runtime
321 321
 }
322 322
 
323
+// Exec returns a new child process
324
+func (p *Init) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
325
+	p.mu.Lock()
326
+	defer p.mu.Unlock()
327
+
328
+	return p.initState.Exec(ctx, path, r)
329
+}
330
+
323 331
 // exec returns a new exec'd process
324
-func (p *Init) exec(context context.Context, path string, r *ExecConfig) (proc.Process, error) {
332
+func (p *Init) exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
325 333
 	// process exec request
326 334
 	var spec specs.Process
327 335
 	if err := json.Unmarshal(r.Spec.Value, &spec); err != nil {
... ...
@@ -342,18 +402,26 @@ func (p *Init) exec(context context.Context, path string, r *ExecConfig) (proc.P
342 342
 		},
343 343
 		waitBlock: make(chan struct{}),
344 344
 	}
345
-	e.State = &execCreatedState{p: e}
345
+	e.execState = &execCreatedState{p: e}
346 346
 	return e, nil
347 347
 }
348 348
 
349
-func (p *Init) checkpoint(context context.Context, r *CheckpointConfig) error {
349
+// Checkpoint the init process
350
+func (p *Init) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
351
+	p.mu.Lock()
352
+	defer p.mu.Unlock()
353
+
354
+	return p.initState.Checkpoint(ctx, r)
355
+}
356
+
357
+func (p *Init) checkpoint(ctx context.Context, r *CheckpointConfig) error {
350 358
 	var actions []runc.CheckpointAction
351 359
 	if !r.Exit {
352 360
 		actions = append(actions, runc.LeaveRunning)
353 361
 	}
354 362
 	work := filepath.Join(p.WorkDir, "criu-work")
355 363
 	defer os.RemoveAll(work)
356
-	if err := p.runtime.Checkpoint(context, p.id, &runc.CheckpointOpts{
364
+	if err := p.runtime.Checkpoint(ctx, p.id, &runc.CheckpointOpts{
357 365
 		WorkDir:                  work,
358 366
 		ImagePath:                r.Path,
359 367
 		AllowOpenTCP:             r.AllowOpenTCP,
... ...
@@ -364,19 +432,27 @@ func (p *Init) checkpoint(context context.Context, r *CheckpointConfig) error {
364 364
 	}, actions...); err != nil {
365 365
 		dumpLog := filepath.Join(p.Bundle, "criu-dump.log")
366 366
 		if cerr := copyFile(dumpLog, filepath.Join(work, "dump.log")); cerr != nil {
367
-			log.G(context).Error(err)
367
+			log.G(ctx).Error(err)
368 368
 		}
369 369
 		return fmt.Errorf("%s path= %s", criuError(err), dumpLog)
370 370
 	}
371 371
 	return nil
372 372
 }
373 373
 
374
-func (p *Init) update(context context.Context, r *google_protobuf.Any) error {
374
+// Update the processes resource configuration
375
+func (p *Init) Update(ctx context.Context, r *google_protobuf.Any) error {
376
+	p.mu.Lock()
377
+	defer p.mu.Unlock()
378
+
379
+	return p.initState.Update(ctx, r)
380
+}
381
+
382
+func (p *Init) update(ctx context.Context, r *google_protobuf.Any) error {
375 383
 	var resources specs.LinuxResources
376 384
 	if err := json.Unmarshal(r.Value, &resources); err != nil {
377 385
 		return err
378 386
 	}
379
-	return p.runtime.Update(context, p.id, &resources)
387
+	return p.runtime.Update(ctx, p.id, &resources)
380 388
 }
381 389
 
382 390
 // Stdio of the process
... ...
@@ -30,16 +30,20 @@ import (
30 30
 	runc "github.com/containerd/go-runc"
31 31
 	google_protobuf "github.com/gogo/protobuf/types"
32 32
 	"github.com/pkg/errors"
33
+	"github.com/sirupsen/logrus"
33 34
 )
34 35
 
35 36
 type initState interface {
36
-	proc.State
37
-
37
+	Resize(console.WinSize) error
38
+	Start(context.Context) error
39
+	Delete(context.Context) error
38 40
 	Pause(context.Context) error
39 41
 	Resume(context.Context) error
40 42
 	Update(context.Context, *google_protobuf.Any) error
41 43
 	Checkpoint(context.Context, *CheckpointConfig) error
42 44
 	Exec(context.Context, string, *ExecConfig) (proc.Process, error)
45
+	Kill(context.Context, uint32, bool) error
46
+	SetExited(int)
43 47
 }
44 48
 
45 49
 type createdState struct {
... ...
@@ -61,43 +65,26 @@ func (s *createdState) transition(name string) error {
61 61
 }
62 62
 
63 63
 func (s *createdState) Pause(ctx context.Context) error {
64
-	s.p.mu.Lock()
65
-	defer s.p.mu.Unlock()
66
-
67 64
 	return errors.Errorf("cannot pause task in created state")
68 65
 }
69 66
 
70 67
 func (s *createdState) Resume(ctx context.Context) error {
71
-	s.p.mu.Lock()
72
-	defer s.p.mu.Unlock()
73
-
74 68
 	return errors.Errorf("cannot resume task in created state")
75 69
 }
76 70
 
77
-func (s *createdState) Update(context context.Context, r *google_protobuf.Any) error {
78
-	s.p.mu.Lock()
79
-	defer s.p.mu.Unlock()
80
-
81
-	return s.p.update(context, r)
71
+func (s *createdState) Update(ctx context.Context, r *google_protobuf.Any) error {
72
+	return s.p.update(ctx, r)
82 73
 }
83 74
 
84
-func (s *createdState) Checkpoint(context context.Context, r *CheckpointConfig) error {
85
-	s.p.mu.Lock()
86
-	defer s.p.mu.Unlock()
87
-
75
+func (s *createdState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
88 76
 	return errors.Errorf("cannot checkpoint a task in created state")
89 77
 }
90 78
 
91 79
 func (s *createdState) Resize(ws console.WinSize) error {
92
-	s.p.mu.Lock()
93
-	defer s.p.mu.Unlock()
94
-
95 80
 	return s.p.resize(ws)
96 81
 }
97 82
 
98 83
 func (s *createdState) Start(ctx context.Context) error {
99
-	s.p.mu.Lock()
100
-	defer s.p.mu.Unlock()
101 84
 	if err := s.p.start(ctx); err != nil {
102 85
 		return err
103 86
 	}
... ...
@@ -105,8 +92,6 @@ func (s *createdState) Start(ctx context.Context) error {
105 105
 }
106 106
 
107 107
 func (s *createdState) Delete(ctx context.Context) error {
108
-	s.p.mu.Lock()
109
-	defer s.p.mu.Unlock()
110 108
 	if err := s.p.delete(ctx); err != nil {
111 109
 		return err
112 110
 	}
... ...
@@ -114,16 +99,10 @@ func (s *createdState) Delete(ctx context.Context) error {
114 114
 }
115 115
 
116 116
 func (s *createdState) Kill(ctx context.Context, sig uint32, all bool) error {
117
-	s.p.mu.Lock()
118
-	defer s.p.mu.Unlock()
119
-
120 117
 	return s.p.kill(ctx, sig, all)
121 118
 }
122 119
 
123 120
 func (s *createdState) SetExited(status int) {
124
-	s.p.mu.Lock()
125
-	defer s.p.mu.Unlock()
126
-
127 121
 	s.p.setExited(status)
128 122
 
129 123
 	if err := s.transition("stopped"); err != nil {
... ...
@@ -132,8 +111,6 @@ func (s *createdState) SetExited(status int) {
132 132
 }
133 133
 
134 134
 func (s *createdState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
135
-	s.p.mu.Lock()
136
-	defer s.p.mu.Unlock()
137 135
 	return s.p.exec(ctx, path, r)
138 136
 }
139 137
 
... ...
@@ -157,43 +134,26 @@ func (s *createdCheckpointState) transition(name string) error {
157 157
 }
158 158
 
159 159
 func (s *createdCheckpointState) Pause(ctx context.Context) error {
160
-	s.p.mu.Lock()
161
-	defer s.p.mu.Unlock()
162
-
163 160
 	return errors.Errorf("cannot pause task in created state")
164 161
 }
165 162
 
166 163
 func (s *createdCheckpointState) Resume(ctx context.Context) error {
167
-	s.p.mu.Lock()
168
-	defer s.p.mu.Unlock()
169
-
170 164
 	return errors.Errorf("cannot resume task in created state")
171 165
 }
172 166
 
173
-func (s *createdCheckpointState) Update(context context.Context, r *google_protobuf.Any) error {
174
-	s.p.mu.Lock()
175
-	defer s.p.mu.Unlock()
176
-
177
-	return s.p.update(context, r)
167
+func (s *createdCheckpointState) Update(ctx context.Context, r *google_protobuf.Any) error {
168
+	return s.p.update(ctx, r)
178 169
 }
179 170
 
180
-func (s *createdCheckpointState) Checkpoint(context context.Context, r *CheckpointConfig) error {
181
-	s.p.mu.Lock()
182
-	defer s.p.mu.Unlock()
183
-
171
+func (s *createdCheckpointState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
184 172
 	return errors.Errorf("cannot checkpoint a task in created state")
185 173
 }
186 174
 
187 175
 func (s *createdCheckpointState) Resize(ws console.WinSize) error {
188
-	s.p.mu.Lock()
189
-	defer s.p.mu.Unlock()
190
-
191 176
 	return s.p.resize(ws)
192 177
 }
193 178
 
194 179
 func (s *createdCheckpointState) Start(ctx context.Context) error {
195
-	s.p.mu.Lock()
196
-	defer s.p.mu.Unlock()
197 180
 	p := s.p
198 181
 	sio := p.stdio
199 182
 
... ...
@@ -247,8 +207,6 @@ func (s *createdCheckpointState) Start(ctx context.Context) error {
247 247
 }
248 248
 
249 249
 func (s *createdCheckpointState) Delete(ctx context.Context) error {
250
-	s.p.mu.Lock()
251
-	defer s.p.mu.Unlock()
252 250
 	if err := s.p.delete(ctx); err != nil {
253 251
 		return err
254 252
 	}
... ...
@@ -256,16 +214,10 @@ func (s *createdCheckpointState) Delete(ctx context.Context) error {
256 256
 }
257 257
 
258 258
 func (s *createdCheckpointState) Kill(ctx context.Context, sig uint32, all bool) error {
259
-	s.p.mu.Lock()
260
-	defer s.p.mu.Unlock()
261
-
262 259
 	return s.p.kill(ctx, sig, all)
263 260
 }
264 261
 
265 262
 func (s *createdCheckpointState) SetExited(status int) {
266
-	s.p.mu.Lock()
267
-	defer s.p.mu.Unlock()
268
-
269 263
 	s.p.setExited(status)
270 264
 
271 265
 	if err := s.transition("stopped"); err != nil {
... ...
@@ -274,9 +226,6 @@ func (s *createdCheckpointState) SetExited(status int) {
274 274
 }
275 275
 
276 276
 func (s *createdCheckpointState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
277
-	s.p.mu.Lock()
278
-	defer s.p.mu.Unlock()
279
-
280 277
 	return nil, errors.Errorf("cannot exec in a created state")
281 278
 }
282 279
 
... ...
@@ -297,67 +246,42 @@ func (s *runningState) transition(name string) error {
297 297
 }
298 298
 
299 299
 func (s *runningState) Pause(ctx context.Context) error {
300
-	s.p.mu.Lock()
301
-	defer s.p.mu.Unlock()
302
-	if err := s.p.pause(ctx); err != nil {
303
-		return err
300
+	if err := s.p.runtime.Pause(ctx, s.p.id); err != nil {
301
+		return s.p.runtimeError(err, "OCI runtime pause failed")
304 302
 	}
303
+
305 304
 	return s.transition("paused")
306 305
 }
307 306
 
308 307
 func (s *runningState) Resume(ctx context.Context) error {
309
-	s.p.mu.Lock()
310
-	defer s.p.mu.Unlock()
311
-
312 308
 	return errors.Errorf("cannot resume a running process")
313 309
 }
314 310
 
315
-func (s *runningState) Update(context context.Context, r *google_protobuf.Any) error {
316
-	s.p.mu.Lock()
317
-	defer s.p.mu.Unlock()
318
-
319
-	return s.p.update(context, r)
311
+func (s *runningState) Update(ctx context.Context, r *google_protobuf.Any) error {
312
+	return s.p.update(ctx, r)
320 313
 }
321 314
 
322 315
 func (s *runningState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
323
-	s.p.mu.Lock()
324
-	defer s.p.mu.Unlock()
325
-
326 316
 	return s.p.checkpoint(ctx, r)
327 317
 }
328 318
 
329 319
 func (s *runningState) Resize(ws console.WinSize) error {
330
-	s.p.mu.Lock()
331
-	defer s.p.mu.Unlock()
332
-
333 320
 	return s.p.resize(ws)
334 321
 }
335 322
 
336 323
 func (s *runningState) Start(ctx context.Context) error {
337
-	s.p.mu.Lock()
338
-	defer s.p.mu.Unlock()
339
-
340 324
 	return errors.Errorf("cannot start a running process")
341 325
 }
342 326
 
343 327
 func (s *runningState) Delete(ctx context.Context) error {
344
-	s.p.mu.Lock()
345
-	defer s.p.mu.Unlock()
346
-
347 328
 	return errors.Errorf("cannot delete a running process")
348 329
 }
349 330
 
350 331
 func (s *runningState) Kill(ctx context.Context, sig uint32, all bool) error {
351
-	s.p.mu.Lock()
352
-	defer s.p.mu.Unlock()
353
-
354 332
 	return s.p.kill(ctx, sig, all)
355 333
 }
356 334
 
357 335
 func (s *runningState) SetExited(status int) {
358
-	s.p.mu.Lock()
359
-	defer s.p.mu.Unlock()
360
-
361 336
 	s.p.setExited(status)
362 337
 
363 338
 	if err := s.transition("stopped"); err != nil {
... ...
@@ -366,8 +290,6 @@ func (s *runningState) SetExited(status int) {
366 366
 }
367 367
 
368 368
 func (s *runningState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
369
-	s.p.mu.Lock()
370
-	defer s.p.mu.Unlock()
371 369
 	return s.p.exec(ctx, path, r)
372 370
 }
373 371
 
... ...
@@ -388,79 +310,54 @@ func (s *pausedState) transition(name string) error {
388 388
 }
389 389
 
390 390
 func (s *pausedState) Pause(ctx context.Context) error {
391
-	s.p.mu.Lock()
392
-	defer s.p.mu.Unlock()
393
-
394 391
 	return errors.Errorf("cannot pause a paused container")
395 392
 }
396 393
 
397 394
 func (s *pausedState) Resume(ctx context.Context) error {
398
-	s.p.mu.Lock()
399
-	defer s.p.mu.Unlock()
400
-
401
-	if err := s.p.resume(ctx); err != nil {
402
-		return err
395
+	if err := s.p.runtime.Resume(ctx, s.p.id); err != nil {
396
+		return s.p.runtimeError(err, "OCI runtime resume failed")
403 397
 	}
398
+
404 399
 	return s.transition("running")
405 400
 }
406 401
 
407
-func (s *pausedState) Update(context context.Context, r *google_protobuf.Any) error {
408
-	s.p.mu.Lock()
409
-	defer s.p.mu.Unlock()
410
-
411
-	return s.p.update(context, r)
402
+func (s *pausedState) Update(ctx context.Context, r *google_protobuf.Any) error {
403
+	return s.p.update(ctx, r)
412 404
 }
413 405
 
414 406
 func (s *pausedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
415
-	s.p.mu.Lock()
416
-	defer s.p.mu.Unlock()
417
-
418 407
 	return s.p.checkpoint(ctx, r)
419 408
 }
420 409
 
421 410
 func (s *pausedState) Resize(ws console.WinSize) error {
422
-	s.p.mu.Lock()
423
-	defer s.p.mu.Unlock()
424
-
425 411
 	return s.p.resize(ws)
426 412
 }
427 413
 
428 414
 func (s *pausedState) Start(ctx context.Context) error {
429
-	s.p.mu.Lock()
430
-	defer s.p.mu.Unlock()
431
-
432 415
 	return errors.Errorf("cannot start a paused process")
433 416
 }
434 417
 
435 418
 func (s *pausedState) Delete(ctx context.Context) error {
436
-	s.p.mu.Lock()
437
-	defer s.p.mu.Unlock()
438
-
439 419
 	return errors.Errorf("cannot delete a paused process")
440 420
 }
441 421
 
442 422
 func (s *pausedState) Kill(ctx context.Context, sig uint32, all bool) error {
443
-	s.p.mu.Lock()
444
-	defer s.p.mu.Unlock()
445
-
446 423
 	return s.p.kill(ctx, sig, all)
447 424
 }
448 425
 
449 426
 func (s *pausedState) SetExited(status int) {
450
-	s.p.mu.Lock()
451
-	defer s.p.mu.Unlock()
452
-
453 427
 	s.p.setExited(status)
454 428
 
429
+	if err := s.p.runtime.Resume(context.Background(), s.p.id); err != nil {
430
+		logrus.WithError(err).Error("resuming exited container from paused state")
431
+	}
432
+
455 433
 	if err := s.transition("stopped"); err != nil {
456 434
 		panic(err)
457 435
 	}
458 436
 }
459 437
 
460 438
 func (s *pausedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
461
-	s.p.mu.Lock()
462
-	defer s.p.mu.Unlock()
463
-
464 439
 	return nil, errors.Errorf("cannot exec in a paused state")
465 440
 }
466 441
 
... ...
@@ -479,50 +376,30 @@ func (s *stoppedState) transition(name string) error {
479 479
 }
480 480
 
481 481
 func (s *stoppedState) Pause(ctx context.Context) error {
482
-	s.p.mu.Lock()
483
-	defer s.p.mu.Unlock()
484
-
485 482
 	return errors.Errorf("cannot pause a stopped container")
486 483
 }
487 484
 
488 485
 func (s *stoppedState) Resume(ctx context.Context) error {
489
-	s.p.mu.Lock()
490
-	defer s.p.mu.Unlock()
491
-
492 486
 	return errors.Errorf("cannot resume a stopped container")
493 487
 }
494 488
 
495
-func (s *stoppedState) Update(context context.Context, r *google_protobuf.Any) error {
496
-	s.p.mu.Lock()
497
-	defer s.p.mu.Unlock()
498
-
489
+func (s *stoppedState) Update(ctx context.Context, r *google_protobuf.Any) error {
499 490
 	return errors.Errorf("cannot update a stopped container")
500 491
 }
501 492
 
502 493
 func (s *stoppedState) Checkpoint(ctx context.Context, r *CheckpointConfig) error {
503
-	s.p.mu.Lock()
504
-	defer s.p.mu.Unlock()
505
-
506 494
 	return errors.Errorf("cannot checkpoint a stopped container")
507 495
 }
508 496
 
509 497
 func (s *stoppedState) Resize(ws console.WinSize) error {
510
-	s.p.mu.Lock()
511
-	defer s.p.mu.Unlock()
512
-
513 498
 	return errors.Errorf("cannot resize a stopped container")
514 499
 }
515 500
 
516 501
 func (s *stoppedState) Start(ctx context.Context) error {
517
-	s.p.mu.Lock()
518
-	defer s.p.mu.Unlock()
519
-
520 502
 	return errors.Errorf("cannot start a stopped process")
521 503
 }
522 504
 
523 505
 func (s *stoppedState) Delete(ctx context.Context) error {
524
-	s.p.mu.Lock()
525
-	defer s.p.mu.Unlock()
526 506
 	if err := s.p.delete(ctx); err != nil {
527 507
 		return err
528 508
 	}
... ...
@@ -538,8 +415,5 @@ func (s *stoppedState) SetExited(status int) {
538 538
 }
539 539
 
540 540
 func (s *stoppedState) Exec(ctx context.Context, path string, r *ExecConfig) (proc.Process, error) {
541
-	s.p.mu.Lock()
542
-	defer s.p.mu.Unlock()
543
-
544 541
 	return nil, errors.Errorf("cannot exec in a stopped state")
545 542
 }
... ...
@@ -31,7 +31,7 @@ import (
31 31
 // ErrNoSuchProcess is returned when the process no longer exists
32 32
 var ErrNoSuchProcess = errors.New("no such process")
33 33
 
34
-const bufferSize = 32
34
+const bufferSize = 2048
35 35
 
36 36
 // Reap should be called when the process receives an SIGCHLD.  Reap will reap
37 37
 // all exited processes and close their wait channels
... ...
@@ -47,7 +47,6 @@ func Reap() error {
47 47
 				Status:    e.Status,
48 48
 			}
49 49
 		}
50
-
51 50
 	}
52 51
 	Default.Unlock()
53 52
 	return err
... ...
@@ -114,9 +114,6 @@ type Service struct {
114 114
 
115 115
 // Create a new initial process and container with the underlying OCI runtime
116 116
 func (s *Service) Create(ctx context.Context, r *shimapi.CreateTaskRequest) (_ *shimapi.CreateTaskResponse, err error) {
117
-	s.mu.Lock()
118
-	defer s.mu.Unlock()
119
-
120 117
 	var mounts []proc.Mount
121 118
 	for _, m := range r.Rootfs {
122 119
 		mounts = append(mounts, proc.Mount{
... ...
@@ -158,6 +155,10 @@ func (s *Service) Create(ctx context.Context, r *shimapi.CreateTaskRequest) (_ *
158 158
 			return nil, errors.Wrapf(err, "failed to mount rootfs component %v", m)
159 159
 		}
160 160
 	}
161
+
162
+	s.mu.Lock()
163
+	defer s.mu.Unlock()
164
+
161 165
 	process, err := newInit(
162 166
 		ctx,
163 167
 		s.config.Path,
... ...
@@ -187,11 +188,9 @@ func (s *Service) Create(ctx context.Context, r *shimapi.CreateTaskRequest) (_ *
187 187
 
188 188
 // Start a process
189 189
 func (s *Service) Start(ctx context.Context, r *shimapi.StartRequest) (*shimapi.StartResponse, error) {
190
-	s.mu.Lock()
191
-	defer s.mu.Unlock()
192
-	p := s.processes[r.ID]
193
-	if p == nil {
194
-		return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process %s", r.ID)
190
+	p, err := s.getExecProcess(r.ID)
191
+	if err != nil {
192
+		return nil, err
195 193
 	}
196 194
 	if err := p.Start(ctx); err != nil {
197 195
 		return nil, err
... ...
@@ -204,16 +203,16 @@ func (s *Service) Start(ctx context.Context, r *shimapi.StartRequest) (*shimapi.
204 204
 
205 205
 // Delete the initial process and container
206 206
 func (s *Service) Delete(ctx context.Context, r *ptypes.Empty) (*shimapi.DeleteResponse, error) {
207
-	s.mu.Lock()
208
-	defer s.mu.Unlock()
209
-	p := s.processes[s.id]
210
-	if p == nil {
211
-		return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
207
+	p, err := s.getInitProcess()
208
+	if err != nil {
209
+		return nil, err
212 210
 	}
213 211
 	if err := p.Delete(ctx); err != nil {
214 212
 		return nil, err
215 213
 	}
214
+	s.mu.Lock()
216 215
 	delete(s.processes, s.id)
216
+	s.mu.Unlock()
217 217
 	s.platform.Close()
218 218
 	return &shimapi.DeleteResponse{
219 219
 		ExitStatus: uint32(p.ExitStatus()),
... ...
@@ -227,11 +226,9 @@ func (s *Service) DeleteProcess(ctx context.Context, r *shimapi.DeleteProcessReq
227 227
 	if r.ID == s.id {
228 228
 		return nil, status.Errorf(codes.InvalidArgument, "cannot delete init process with DeleteProcess")
229 229
 	}
230
-	s.mu.Lock()
231
-	p := s.processes[r.ID]
232
-	s.mu.Unlock()
233
-	if p == nil {
234
-		return nil, errors.Wrapf(errdefs.ErrNotFound, "process %s", r.ID)
230
+	p, err := s.getExecProcess(r.ID)
231
+	if err != nil {
232
+		return nil, err
235 233
 	}
236 234
 	if err := p.Delete(ctx); err != nil {
237 235
 		return nil, err
... ...
@@ -249,13 +246,14 @@ func (s *Service) DeleteProcess(ctx context.Context, r *shimapi.DeleteProcessReq
249 249
 // Exec an additional process inside the container
250 250
 func (s *Service) Exec(ctx context.Context, r *shimapi.ExecProcessRequest) (*ptypes.Empty, error) {
251 251
 	s.mu.Lock()
252
-	defer s.mu.Unlock()
253 252
 
254 253
 	if p := s.processes[r.ID]; p != nil {
254
+		s.mu.Unlock()
255 255
 		return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ID)
256 256
 	}
257 257
 
258 258
 	p := s.processes[s.id]
259
+	s.mu.Unlock()
259 260
 	if p == nil {
260 261
 		return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
261 262
 	}
... ...
@@ -271,14 +269,14 @@ func (s *Service) Exec(ctx context.Context, r *shimapi.ExecProcessRequest) (*pty
271 271
 	if err != nil {
272 272
 		return nil, errdefs.ToGRPC(err)
273 273
 	}
274
+	s.mu.Lock()
274 275
 	s.processes[r.ID] = process
276
+	s.mu.Unlock()
275 277
 	return empty, nil
276 278
 }
277 279
 
278 280
 // ResizePty of a process
279 281
 func (s *Service) ResizePty(ctx context.Context, r *shimapi.ResizePtyRequest) (*ptypes.Empty, error) {
280
-	s.mu.Lock()
281
-	defer s.mu.Unlock()
282 282
 	if r.ID == "" {
283 283
 		return nil, errdefs.ToGRPCf(errdefs.ErrInvalidArgument, "id not provided")
284 284
 	}
... ...
@@ -286,7 +284,9 @@ func (s *Service) ResizePty(ctx context.Context, r *shimapi.ResizePtyRequest) (*
286 286
 		Width:  uint16(r.Width),
287 287
 		Height: uint16(r.Height),
288 288
 	}
289
+	s.mu.Lock()
289 290
 	p := s.processes[r.ID]
291
+	s.mu.Unlock()
290 292
 	if p == nil {
291 293
 		return nil, errors.Errorf("process does not exist %s", r.ID)
292 294
 	}
... ...
@@ -298,11 +298,9 @@ func (s *Service) ResizePty(ctx context.Context, r *shimapi.ResizePtyRequest) (*
298 298
 
299 299
 // State returns runtime state information for a process
300 300
 func (s *Service) State(ctx context.Context, r *shimapi.StateRequest) (*shimapi.StateResponse, error) {
301
-	s.mu.Lock()
302
-	defer s.mu.Unlock()
303
-	p := s.processes[r.ID]
304
-	if p == nil {
305
-		return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process id %s", r.ID)
301
+	p, err := s.getExecProcess(r.ID)
302
+	if err != nil {
303
+		return nil, err
306 304
 	}
307 305
 	st, err := p.Status(ctx)
308 306
 	if err != nil {
... ...
@@ -338,11 +336,9 @@ func (s *Service) State(ctx context.Context, r *shimapi.StateRequest) (*shimapi.
338 338
 
339 339
 // Pause the container
340 340
 func (s *Service) Pause(ctx context.Context, r *ptypes.Empty) (*ptypes.Empty, error) {
341
-	s.mu.Lock()
342
-	defer s.mu.Unlock()
343
-	p := s.processes[s.id]
344
-	if p == nil {
345
-		return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
341
+	p, err := s.getInitProcess()
342
+	if err != nil {
343
+		return nil, err
346 344
 	}
347 345
 	if err := p.(*proc.Init).Pause(ctx); err != nil {
348 346
 		return nil, err
... ...
@@ -352,11 +348,9 @@ func (s *Service) Pause(ctx context.Context, r *ptypes.Empty) (*ptypes.Empty, er
352 352
 
353 353
 // Resume the container
354 354
 func (s *Service) Resume(ctx context.Context, r *ptypes.Empty) (*ptypes.Empty, error) {
355
-	s.mu.Lock()
356
-	defer s.mu.Unlock()
357
-	p := s.processes[s.id]
358
-	if p == nil {
359
-		return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
355
+	p, err := s.getInitProcess()
356
+	if err != nil {
357
+		return nil, err
360 358
 	}
361 359
 	if err := p.(*proc.Init).Resume(ctx); err != nil {
362 360
 		return nil, err
... ...
@@ -366,12 +360,10 @@ func (s *Service) Resume(ctx context.Context, r *ptypes.Empty) (*ptypes.Empty, e
366 366
 
367 367
 // Kill a process with the provided signal
368 368
 func (s *Service) Kill(ctx context.Context, r *shimapi.KillRequest) (*ptypes.Empty, error) {
369
-	s.mu.Lock()
370
-	defer s.mu.Unlock()
371 369
 	if r.ID == "" {
372
-		p := s.processes[s.id]
373
-		if p == nil {
374
-			return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
370
+		p, err := s.getInitProcess()
371
+		if err != nil {
372
+			return nil, err
375 373
 		}
376 374
 		if err := p.Kill(ctx, r.Signal, r.All); err != nil {
377 375
 			return nil, errdefs.ToGRPC(err)
... ...
@@ -379,9 +371,9 @@ func (s *Service) Kill(ctx context.Context, r *shimapi.KillRequest) (*ptypes.Emp
379 379
 		return empty, nil
380 380
 	}
381 381
 
382
-	p := s.processes[r.ID]
383
-	if p == nil {
384
-		return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process id %s not found", r.ID)
382
+	p, err := s.getExecProcess(r.ID)
383
+	if err != nil {
384
+		return nil, err
385 385
 	}
386 386
 	if err := p.Kill(ctx, r.Signal, r.All); err != nil {
387 387
 		return nil, errdefs.ToGRPC(err)
... ...
@@ -422,11 +414,9 @@ func (s *Service) ListPids(ctx context.Context, r *shimapi.ListPidsRequest) (*sh
422 422
 
423 423
 // CloseIO of a process
424 424
 func (s *Service) CloseIO(ctx context.Context, r *shimapi.CloseIORequest) (*ptypes.Empty, error) {
425
-	s.mu.Lock()
426
-	defer s.mu.Unlock()
427
-	p := s.processes[r.ID]
428
-	if p == nil {
429
-		return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process does not exist %s", r.ID)
425
+	p, err := s.getExecProcess(r.ID)
426
+	if err != nil {
427
+		return nil, err
430 428
 	}
431 429
 	if stdin := p.Stdin(); stdin != nil {
432 430
 		if err := stdin.Close(); err != nil {
... ...
@@ -438,11 +428,9 @@ func (s *Service) CloseIO(ctx context.Context, r *shimapi.CloseIORequest) (*ptyp
438 438
 
439 439
 // Checkpoint the container
440 440
 func (s *Service) Checkpoint(ctx context.Context, r *shimapi.CheckpointTaskRequest) (*ptypes.Empty, error) {
441
-	s.mu.Lock()
442
-	defer s.mu.Unlock()
443
-	p := s.processes[s.id]
444
-	if p == nil {
445
-		return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
441
+	p, err := s.getInitProcess()
442
+	if err != nil {
443
+		return nil, err
446 444
 	}
447 445
 	var options runctypes.CheckpointOptions
448 446
 	if r.Options != nil {
... ...
@@ -475,11 +463,9 @@ func (s *Service) ShimInfo(ctx context.Context, r *ptypes.Empty) (*shimapi.ShimI
475 475
 
476 476
 // Update a running container
477 477
 func (s *Service) Update(ctx context.Context, r *shimapi.UpdateTaskRequest) (*ptypes.Empty, error) {
478
-	s.mu.Lock()
479
-	defer s.mu.Unlock()
480
-	p := s.processes[s.id]
481
-	if p == nil {
482
-		return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
478
+	p, err := s.getInitProcess()
479
+	if err != nil {
480
+		return nil, err
483 481
 	}
484 482
 	if err := p.(*proc.Init).Update(ctx, r.Resources); err != nil {
485 483
 		return nil, errdefs.ToGRPC(err)
... ...
@@ -489,11 +475,9 @@ func (s *Service) Update(ctx context.Context, r *shimapi.UpdateTaskRequest) (*pt
489 489
 
490 490
 // Wait for a process to exit
491 491
 func (s *Service) Wait(ctx context.Context, r *shimapi.WaitRequest) (*shimapi.WaitResponse, error) {
492
-	s.mu.Lock()
493
-	p := s.processes[r.ID]
494
-	s.mu.Unlock()
495
-	if p == nil {
496
-		return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
492
+	p, err := s.getExecProcess(r.ID)
493
+	if err != nil {
494
+		return nil, err
497 495
 	}
498 496
 	p.Wait()
499 497
 
... ...
@@ -509,16 +493,24 @@ func (s *Service) processExits() {
509 509
 	}
510 510
 }
511 511
 
512
-func (s *Service) checkProcesses(e runc.Exit) {
512
+func (s *Service) allProcesses() []rproc.Process {
513 513
 	s.mu.Lock()
514 514
 	defer s.mu.Unlock()
515 515
 
516
+	res := make([]rproc.Process, 0, len(s.processes))
517
+	for _, p := range s.processes {
518
+		res = append(res, p)
519
+	}
520
+	return res
521
+}
522
+
523
+func (s *Service) checkProcesses(e runc.Exit) {
516 524
 	shouldKillAll, err := shouldKillAllOnExit(s.bundle)
517 525
 	if err != nil {
518 526
 		log.G(s.context).WithError(err).Error("failed to check shouldKillAll")
519 527
 	}
520 528
 
521
-	for _, p := range s.processes {
529
+	for _, p := range s.allProcesses() {
522 530
 		if p.Pid() == e.Pid {
523 531
 
524 532
 			if shouldKillAll {
... ...
@@ -563,11 +555,9 @@ func shouldKillAllOnExit(bundlePath string) (bool, error) {
563 563
 }
564 564
 
565 565
 func (s *Service) getContainerPids(ctx context.Context, id string) ([]uint32, error) {
566
-	s.mu.Lock()
567
-	defer s.mu.Unlock()
568
-	p := s.processes[s.id]
569
-	if p == nil {
570
-		return nil, errors.Wrapf(errdefs.ErrFailedPrecondition, "container must be created")
566
+	p, err := s.getInitProcess()
567
+	if err != nil {
568
+		return nil, err
571 569
 	}
572 570
 
573 571
 	ps, err := p.(*proc.Init).Runtime().Ps(ctx, id)
... ...
@@ -589,6 +579,30 @@ func (s *Service) forward(publisher events.Publisher) {
589 589
 	}
590 590
 }
591 591
 
592
+// getInitProcess returns initial process
593
+func (s *Service) getInitProcess() (rproc.Process, error) {
594
+	s.mu.Lock()
595
+	defer s.mu.Unlock()
596
+
597
+	p := s.processes[s.id]
598
+	if p == nil {
599
+		return nil, errdefs.ToGRPCf(errdefs.ErrFailedPrecondition, "container must be created")
600
+	}
601
+	return p, nil
602
+}
603
+
604
+// getExecProcess returns exec process
605
+func (s *Service) getExecProcess(id string) (rproc.Process, error) {
606
+	s.mu.Lock()
607
+	defer s.mu.Unlock()
608
+
609
+	p := s.processes[id]
610
+	if p == nil {
611
+		return nil, errdefs.ToGRPCf(errdefs.ErrNotFound, "process %s does not exist", id)
612
+	}
613
+	return p, nil
614
+}
615
+
592 616
 func getTopic(ctx context.Context, e interface{}) string {
593 617
 	switch e.(type) {
594 618
 	case *eventstypes.TaskCreate:
... ...
@@ -20,8 +20,8 @@ github.com/gogo/protobuf v1.0.0
20 20
 github.com/gogo/googleapis 08a7655d27152912db7aaf4f983275eaf8d128ef
21 21
 github.com/golang/protobuf v1.1.0
22 22
 github.com/opencontainers/runtime-spec eba862dc2470385a233c7507392675cbeadf7353 # v1.0.1-45-geba862d
23
-github.com/opencontainers/runc 58592df56734acf62e574865fe40b9e53e967910
24
-github.com/sirupsen/logrus v1.0.0
23
+github.com/opencontainers/runc 10d38b660a77168360df3522881e2dc2be5056bd
24
+github.com/sirupsen/logrus v1.0.3
25 25
 github.com/urfave/cli 7bc6a0acffa589f415f88aca16cc1de5ffd66f9c
26 26
 golang.org/x/net b3756b4b77d7b13260a0a2ec658753cf48922eac
27 27
 google.golang.org/grpc v1.12.0
... ...
@@ -33,7 +33,7 @@ golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
33 33
 github.com/BurntSushi/toml a368813c5e648fee92e5f6c30e3944ff9d5e8895
34 34
 github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
35 35
 github.com/Microsoft/go-winio v0.4.11
36
-github.com/Microsoft/hcsshim v0.7.12
36
+github.com/Microsoft/hcsshim v0.8.1
37 37
 google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
38 38
 golang.org/x/text 19e51611da83d6be54ddafce4a4af510cb3e9ea4
39 39
 github.com/containerd/ttrpc 2a805f71863501300ae1976d29f0454ae003e85a
... ...
@@ -81,9 +81,9 @@ k8s.io/kubernetes v1.12.0
81 81
 k8s.io/utils cd34563cd63c2bd7c6fe88a73c4dcf34ed8a67cb
82 82
 
83 83
 # zfs dependencies
84
-github.com/containerd/zfs 9a0b8b8b5982014b729cd34eb7cd7a11062aa6ec
84
+github.com/containerd/zfs 9f6ef3b1fe5144bd91fe5855b4eba81bc0d17d03
85 85
 github.com/mistifyio/go-zfs 166add352731e515512690329794ee593f1aaff2
86 86
 github.com/pborman/uuid c65b2f87fee37d1c7854c9164a450713c28d50cd
87 87
 
88 88
 # aufs dependencies
89
-github.com/containerd/aufs ffa39970e26ad01d81f540b21e65f9c1841a5f92
89
+github.com/containerd/aufs da3cf16bfbe68ba8f114f1536a05c01528a25434
... ...
@@ -68,6 +68,7 @@ make BUILDTAGS='seccomp apparmor'
68 68
 | selinux   | selinux process and mount labeling | <none>      |
69 69
 | apparmor  | apparmor profile support           | <none>      |
70 70
 | ambient   | ambient capability support         | kernel 4.3  |
71
+| nokmem    | disable kernel memory account      | <none>      |
71 72
 
72 73
 
73 74
 ### Running the test suite
... ...
@@ -148,6 +148,7 @@ config := &configs.Config{
148 148
 		{Type: configs.NEWPID},
149 149
 		{Type: configs.NEWUSER},
150 150
 		{Type: configs.NEWNET},
151
+		{Type: configs.NEWCGROUP},
151 152
 	}),
152 153
 	Cgroups: &configs.Cgroup{
153 154
 		Name:   "test-container",
... ...
@@ -17,7 +17,7 @@ import (
17 17
 )
18 18
 
19 19
 const (
20
-	cgroupNamePrefix = "name="
20
+	CgroupNamePrefix = "name="
21 21
 	CgroupProcesses  = "cgroup.procs"
22 22
 )
23 23
 
... ...
@@ -156,8 +156,8 @@ func getCgroupMountsHelper(ss map[string]bool, mi io.Reader, all bool) ([]Mount,
156 156
 				continue
157 157
 			}
158 158
 			ss[opt] = true
159
-			if strings.HasPrefix(opt, cgroupNamePrefix) {
160
-				opt = opt[len(cgroupNamePrefix):]
159
+			if strings.HasPrefix(opt, CgroupNamePrefix) {
160
+				opt = opt[len(CgroupNamePrefix):]
161 161
 			}
162 162
 			m.Subsystems = append(m.Subsystems, opt)
163 163
 			numFound++
... ...
@@ -343,7 +343,7 @@ func getControllerPath(subsystem string, cgroups map[string]string) (string, err
343 343
 		return p, nil
344 344
 	}
345 345
 
346
-	if p, ok := cgroups[cgroupNamePrefix+subsystem]; ok {
346
+	if p, ok := cgroups[CgroupNamePrefix+subsystem]; ok {
347 347
 		return p, nil
348 348
 	}
349 349
 
... ...
@@ -7,12 +7,13 @@ import (
7 7
 )
8 8
 
9 9
 const (
10
-	NEWNET  NamespaceType = "NEWNET"
11
-	NEWPID  NamespaceType = "NEWPID"
12
-	NEWNS   NamespaceType = "NEWNS"
13
-	NEWUTS  NamespaceType = "NEWUTS"
14
-	NEWIPC  NamespaceType = "NEWIPC"
15
-	NEWUSER NamespaceType = "NEWUSER"
10
+	NEWNET    NamespaceType = "NEWNET"
11
+	NEWPID    NamespaceType = "NEWPID"
12
+	NEWNS     NamespaceType = "NEWNS"
13
+	NEWUTS    NamespaceType = "NEWUTS"
14
+	NEWIPC    NamespaceType = "NEWIPC"
15
+	NEWUSER   NamespaceType = "NEWUSER"
16
+	NEWCGROUP NamespaceType = "NEWCGROUP"
16 17
 )
17 18
 
18 19
 var (
... ...
@@ -35,6 +36,8 @@ func NsName(ns NamespaceType) string {
35 35
 		return "user"
36 36
 	case NEWUTS:
37 37
 		return "uts"
38
+	case NEWCGROUP:
39
+		return "cgroup"
38 40
 	}
39 41
 	return ""
40 42
 }
... ...
@@ -68,6 +71,7 @@ func NamespaceTypes() []NamespaceType {
68 68
 		NEWNET,
69 69
 		NEWPID,
70 70
 		NEWNS,
71
+		NEWCGROUP,
71 72
 	}
72 73
 }
73 74
 
... ...
@@ -9,12 +9,13 @@ func (n *Namespace) Syscall() int {
9 9
 }
10 10
 
11 11
 var namespaceInfo = map[NamespaceType]int{
12
-	NEWNET:  unix.CLONE_NEWNET,
13
-	NEWNS:   unix.CLONE_NEWNS,
14
-	NEWUSER: unix.CLONE_NEWUSER,
15
-	NEWIPC:  unix.CLONE_NEWIPC,
16
-	NEWUTS:  unix.CLONE_NEWUTS,
17
-	NEWPID:  unix.CLONE_NEWPID,
12
+	NEWNET:    unix.CLONE_NEWNET,
13
+	NEWNS:     unix.CLONE_NEWNS,
14
+	NEWUSER:   unix.CLONE_NEWUSER,
15
+	NEWIPC:    unix.CLONE_NEWIPC,
16
+	NEWUTS:    unix.CLONE_NEWUTS,
17
+	NEWPID:    unix.CLONE_NEWPID,
18
+	NEWCGROUP: unix.CLONE_NEWCGROUP,
18 19
 }
19 20
 
20 21
 // CloneFlags parses the container's Namespaces options to set the correct
... ...
@@ -42,6 +42,12 @@ enum sync_t {
42 42
 	SYNC_ERR = 0xFF,	/* Fatal error, no turning back. The error code follows. */
43 43
 };
44 44
 
45
+/*
46
+ * Synchronisation value for cgroup namespace setup.
47
+ * The same constant is defined in process_linux.go as "createCgroupns".
48
+ */
49
+#define CREATECGROUPNS 0x80
50
+
45 51
 /* longjmp() arguments. */
46 52
 #define JUMP_PARENT 0x00
47 53
 #define JUMP_CHILD  0xA0
... ...
@@ -640,7 +646,6 @@ void nsexec(void)
640 640
 	case JUMP_PARENT:{
641 641
 			int len;
642 642
 			pid_t child, first_child = -1;
643
-			char buf[JSON_MAX];
644 643
 			bool ready = false;
645 644
 
646 645
 			/* For debugging. */
... ...
@@ -716,6 +721,18 @@ void nsexec(void)
716 716
 							kill(child, SIGKILL);
717 717
 							bail("failed to sync with child: write(SYNC_RECVPID_ACK)");
718 718
 						}
719
+
720
+						/* Send the init_func pid back to our parent.
721
+						 *
722
+						 * Send the init_func pid and the pid of the first child back to our parent.
723
+						 * We need to send both back because we can't reap the first child we created (CLONE_PARENT).
724
+						 * It becomes the responsibility of our parent to reap the first child.
725
+						 */
726
+						len = dprintf(pipenum, "{\"pid\": %d, \"pid_first\": %d}\n", child, first_child);
727
+						if (len < 0) {
728
+							kill(child, SIGKILL);
729
+							bail("unable to generate JSON for child pid");
730
+						}
719 731
 					}
720 732
 					break;
721 733
 				case SYNC_CHILD_READY:
... ...
@@ -759,23 +776,6 @@ void nsexec(void)
759 759
 					bail("unexpected sync value: %u", s);
760 760
 				}
761 761
 			}
762
-
763
-			/*
764
-			 * Send the init_func pid and the pid of the first child back to our parent.
765
-			 *
766
-			 * We need to send both back because we can't reap the first child we created (CLONE_PARENT).
767
-			 * It becomes the responsibility of our parent to reap the first child.
768
-			 */
769
-			len = snprintf(buf, JSON_MAX, "{\"pid\": %d, \"pid_first\": %d}\n", child, first_child);
770
-			if (len < 0) {
771
-				kill(child, SIGKILL);
772
-				bail("unable to generate JSON for child pid");
773
-			}
774
-			if (write(pipenum, buf, len) != len) {
775
-				kill(child, SIGKILL);
776
-				bail("unable to send child pid to bootstrapper");
777
-			}
778
-
779 762
 			exit(0);
780 763
 		}
781 764
 
... ...
@@ -862,14 +862,17 @@ void nsexec(void)
862 862
 				if (setresuid(0, 0, 0) < 0)
863 863
 					bail("failed to become root in user namespace");
864 864
 			}
865
-
866 865
 			/*
867
-			 * Unshare all of the namespaces. Note that we don't merge this
868
-			 * with clone() because there were some old kernel versions where
869
-			 * clone(CLONE_PARENT | CLONE_NEWPID) was broken, so we'll just do
870
-			 * it the long way.
866
+			 * Unshare all of the namespaces. Now, it should be noted that this
867
+			 * ordering might break in the future (especially with rootless
868
+			 * containers). But for now, it's not possible to split this into
869
+			 * CLONE_NEWUSER + [the rest] because of some RHEL SELinux issues.
870
+			 *
871
+			 * Note that we don't merge this with clone() because there were
872
+			 * some old kernel versions where clone(CLONE_PARENT | CLONE_NEWPID)
873
+			 * was broken, so we'll just do it the long way anyway.
871 874
 			 */
872
-			if (unshare(config.cloneflags) < 0)
875
+			if (unshare(config.cloneflags & ~CLONE_NEWCGROUP) < 0)
873 876
 				bail("failed to unshare namespaces");
874 877
 
875 878
 			/*
... ...
@@ -958,6 +961,18 @@ void nsexec(void)
958 958
 					bail("setgroups failed");
959 959
 			}
960 960
 
961
+			/* ... wait until our topmost parent has finished cgroup setup in p.manager.Apply() ... */
962
+			if (config.cloneflags & CLONE_NEWCGROUP) {
963
+				uint8_t value;
964
+				if (read(pipenum, &value, sizeof(value)) != sizeof(value))
965
+					bail("read synchronisation value failed");
966
+				if (value == CREATECGROUPNS) {
967
+					if (unshare(CLONE_NEWCGROUP) < 0)
968
+						bail("failed to unshare cgroup namespace");
969
+				} else
970
+					bail("received unknown synchronisation value");
971
+			}
972
+
961 973
 			s = SYNC_CHILD_READY;
962 974
 			if (write(syncfd, &s, sizeof(s)) != sizeof(s))
963 975
 				bail("failed to sync with patent: write(SYNC_CHILD_READY)");