Skip to content

Commit

Permalink
Merge pull request #3365 from crosbymichael/exec-lk
Browse files Browse the repository at this point in the history
Reserve exec id to prevent race
  • Loading branch information
estesp committed Jun 25, 2019
2 parents b2662f2 + 1a8df3f commit 2875825
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 13 deletions.
41 changes: 30 additions & 11 deletions runtime/v2/runc/container.go
Expand Up @@ -125,10 +125,11 @@ func NewContainer(ctx context.Context, platform rproc.Platform, r *task.CreateTa
return nil, errdefs.ToGRPC(err)
}
container := &Container{
ID: r.ID,
Bundle: r.Bundle,
process: process,
processes: make(map[string]rproc.Process),
ID: r.ID,
Bundle: r.Bundle,
process: process,
processes: make(map[string]rproc.Process),
reservedProcess: make(map[string]struct{}),
}
pid := process.Pid()
if pid > 0 {
Expand Down Expand Up @@ -189,9 +190,10 @@ type Container struct {
// Bundle path
Bundle string

cgroup cgroups.Cgroup
process rproc.Process
processes map[string]rproc.Process
cgroup cgroups.Cgroup
process rproc.Process
processes map[string]rproc.Process
reservedProcess map[string]struct{}
}

// All processes in the container
Expand Down Expand Up @@ -256,18 +258,35 @@ func (c *Container) Process(id string) (rproc.Process, error) {
return p, nil
}

// ProcessExists returns true if the process by id exists
func (c *Container) ProcessExists(id string) bool {
// ReserveProcess checks for the existence of an id and atomically
// reserves the process id if it does not already exist
//
// Returns true if the process id was sucessfully reserved and a
// cancel func to release the reservation
func (c *Container) ReserveProcess(id string) (bool, func()) {
c.mu.Lock()
defer c.mu.Unlock()
_, ok := c.processes[id]
return ok

if _, ok := c.processes[id]; ok {
return false, nil
}
if _, ok := c.reservedProcess[id]; ok {
return false, nil
}
c.reservedProcess[id] = struct{}{}
return true, func() {
c.mu.Lock()
defer c.mu.Unlock()
delete(c.reservedProcess, id)
}
}

// ProcessAdd adds a new process to the container
func (c *Container) ProcessAdd(process rproc.Process) {
c.mu.Lock()
defer c.mu.Unlock()

delete(c.reservedProcess, process.ID())
c.processes[process.ID()] = process
}

Expand Down
4 changes: 3 additions & 1 deletion runtime/v2/runc/v1/service.go
Expand Up @@ -326,11 +326,13 @@ func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*pty
if err != nil {
return nil, err
}
if container.ProcessExists(r.ExecID) {
ok, cancel := container.ReserveProcess(r.ExecID)
if !ok {
return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ExecID)
}
process, err := container.Exec(ctx, r)
if err != nil {
cancel()
return nil, errdefs.ToGRPC(err)
}

Expand Down
4 changes: 3 additions & 1 deletion runtime/v2/runc/v2/service.go
Expand Up @@ -375,11 +375,13 @@ func (s *service) Exec(ctx context.Context, r *taskAPI.ExecProcessRequest) (*pty
if err != nil {
return nil, err
}
if container.ProcessExists(r.ExecID) {
ok, cancel := container.ReserveProcess(r.ExecID)
if !ok {
return nil, errdefs.ToGRPCf(errdefs.ErrAlreadyExists, "id %s", r.ExecID)
}
process, err := container.Exec(ctx, r)
if err != nil {
cancel()
return nil, errdefs.ToGRPC(err)
}

Expand Down

0 comments on commit 2875825

Please sign in to comment.