Skip to content
This repository has been archived by the owner on May 12, 2021. It is now read-only.

Commit

Permalink
virtcontainers: store: Add a ItemLock API
Browse files Browse the repository at this point in the history
The ItemLock API allows for taking shared and exclusive locks on all
items.
For virtcontainers, this is specialized into taking locks on the Lock
item, and will be used for sandbox locking.

Signed-off-by: Samuel Ortiz <[email protected]>
  • Loading branch information
Samuel Ortiz committed Feb 6, 2019
1 parent 6e9256f commit 2ecffda
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 0 deletions.
2 changes: 2 additions & 0 deletions virtcontainers/store/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,6 @@ type backend interface {
// The caller gets an item URL back and handles it directly,
// outside of the top level Store API.
raw(id string) (string, error)
lock(item Item, exclusive bool) (string, error)
unlock(item Item, token string) error
}
50 changes: 50 additions & 0 deletions virtcontainers/store/filesystem_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import (
"io/ioutil"
"os"
"path/filepath"
"syscall"

"github.com/kata-containers/runtime/virtcontainers/pkg/uuid"
opentracing "github.com/opentracing/opentracing-go"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -103,6 +105,8 @@ type filesystem struct {

path string
rawPath string

lockTokens map[string]*os.File
}

// Logger returns a logrus logger appropriate for logging Store filesystem messages
Expand Down Expand Up @@ -174,6 +178,7 @@ func (f *filesystem) new(ctx context.Context, path string, host string) error {
f.ctx = ctx
f.path = path
f.rawPath = filepath.Join(f.path, "raw")
f.lockTokens = make(map[string]*os.File)

f.logger().Debugf("New filesystem store backend for %s", path)

Expand Down Expand Up @@ -259,3 +264,48 @@ func (f *filesystem) raw(id string) (string, error) {

return filesystemScheme + "://" + file.Name(), nil
}

func (f *filesystem) lock(item Item, exclusive bool) (string, error) {
itemPath, err := f.itemToPath(item)
if err != nil {
return "", err
}

itemFile, err := os.Open(itemPath)
if err != nil {
return "", err
}

var lockType int
if exclusive {
lockType = syscall.LOCK_EX
} else {
lockType = syscall.LOCK_SH
}

if err := syscall.Flock(int(itemFile.Fd()), lockType); err != nil {
itemFile.Close()
return "", err
}

token := uuid.Generate().String()
f.lockTokens[token] = itemFile

return token, nil
}

func (f *filesystem) unlock(item Item, token string) error {
itemFile := f.lockTokens[token]
if itemFile == nil {
return fmt.Errorf("No lock for token %s", token)
}

if err := syscall.Flock(int(itemFile.Fd()), syscall.LOCK_UN); err != nil {
return err
}

itemFile.Close()
delete(f.lockTokens, token)

return nil
}
48 changes: 48 additions & 0 deletions virtcontainers/store/filesystem_backend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,51 @@ func TestStoreFilesystemRaw(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, path, filesystemScheme+"://"+filepath.Join(rootPath, "raw", "roah"))
}

func TestStoreFilesystemLockShared(t *testing.T) {
f := filesystem{}

err := f.new(context.Background(), rootPath, "")
defer f.delete()
assert.Nil(t, err)

// Take 2 shared locks
token1, err := f.lock(Lock, false)
assert.Nil(t, err)

token2, err := f.lock(Lock, false)
assert.Nil(t, err)

err = f.unlock(Lock, token1)
assert.Nil(t, err)

err = f.unlock(Lock, token2)
assert.Nil(t, err)

err = f.unlock(Lock, token2)
assert.NotNil(t, err)
}

func TestStoreFilesystemLockExclusive(t *testing.T) {
f := filesystem{}

err := f.new(context.Background(), rootPath, "")
defer f.delete()
assert.Nil(t, err)

// Take 1 exclusive lock
token, err := f.lock(Lock, true)
assert.Nil(t, err)

err = f.unlock(Lock, token)
assert.Nil(t, err)

token, err = f.lock(Lock, true)
assert.Nil(t, err)

err = f.unlock(Lock, token)
assert.Nil(t, err)

err = f.unlock(Lock, token)
assert.NotNil(t, err)
}
10 changes: 10 additions & 0 deletions virtcontainers/store/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,13 @@ func (s *Store) Raw(id string) (string, error) {

return s.backend.raw(id)
}

// ItemLock takes a lock on an item.
func (s *Store) ItemLock(item Item, exclusive bool) (string, error) {
return s.backend.lock(item, exclusive)
}

// ItemUnlock unlocks an item.
func (s *Store) ItemUnlock(item Item, token string) error {
return s.backend.unlock(item, token)
}
15 changes: 15 additions & 0 deletions virtcontainers/store/vc.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,21 @@ func (s *VCStore) Raw(id string) (string, error) {
return s.state.Raw(id)
}

// Lock takes an exclusive lock on the virtcontainers state Lock item.
func (s *VCStore) Lock() (string, error) {
return s.state.ItemLock(Lock, true)
}

// RLock takes a shared lock on the virtcontainers state Lock item.
func (s *VCStore) RLock() (string, error) {
return s.state.ItemLock(Lock, false)
}

// Unlock unlocks the virtcontainers state Lock item.
func (s *VCStore) Unlock(token string) error {
return s.state.ItemUnlock(Lock, token)
}

// Utilities for virtcontainers

// SandboxConfigurationRoot returns a virtcontainers sandbox configuration root URL.
Expand Down

0 comments on commit 2ecffda

Please sign in to comment.