Skip to content

Commit

Permalink
Add feature checking support to go-criu
Browse files Browse the repository at this point in the history
This adds the feature checking interface with the same semantics as the
feature checking through libcriu.

Signed-off-by: Adrian Reber <[email protected]>
  • Loading branch information
adrianreber committed Dec 16, 2021
1 parent bbf788d commit 5b3b8ad
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 5 deletions.
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ SHELL = /bin/bash
GO ?= go
CC ?= gcc
COVERAGE_PATH ?= $(shell pwd)/.coverage
CRIU_FEATURE_MEM_TRACK = $(shell if criu check --feature mem_dirty_track > /dev/null; then echo 1; else echo 0; fi)
CRIU_FEATURE_LAZY_PAGES = $(shell if criu check --feature uffd-noncoop > /dev/null; then echo 1; else echo 0; fi)
CRIU_FEATURE_PIDFD_STORE = $(shell if criu check --feature pidfd_store > /dev/null; then echo 1; else echo 0; fi)

export CRIU_FEATURE_MEM_TRACK CRIU_FEATURE_LAZY_PAGES CRIU_FEATURE_PIDFD_STORE

all: build test phaul-test

Expand Down
45 changes: 45 additions & 0 deletions features.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package criu

import (
"fmt"

"github.com/checkpoint-restore/go-criu/v5/rpc"
)

// Feature checking in go-criu is based on the libcriu feature checking function.

// Feature checking allows the user to check if CRIU supports
// certain features. There are CRIU features which do not depend
// on the version of CRIU but on kernel features or architecture.
//
// One example is memory tracking. Memory tracking can be disabled
// in the kernel or there are architectures which do not support
// it (aarch64 for example). By using the feature check a libcriu
// user can easily query CRIU if a certain feature is available.
//
// The features which should be checked can be marked in the
// structure 'struct criu_feature_check'. Each structure member
// that is set to true will result in CRIU checking for the
// availability of that feature in the current combination of
// CRIU/kernel/architecture.
//
// Available features will be set to true when the function
// returns successfully. Missing features will be set to false.

func (c *Criu) FeatureCheck(features *rpc.CriuFeatures) (*rpc.CriuFeatures, error) {
resp, err := c.doSwrkWithResp(
rpc.CriuReqType_FEATURE_CHECK,
nil,
nil,
features,
)
if err != nil {
return nil, err
}

if resp.GetType() != rpc.CriuReqType_FEATURE_CHECK {
return nil, fmt.Errorf("Unexpected CRIU RPC response")
}

return features, nil
}
14 changes: 9 additions & 5 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,19 +87,19 @@ func (c *Criu) sendAndRecv(reqB []byte) ([]byte, int, error) {
}

func (c *Criu) doSwrk(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) error {
resp, err := c.doSwrkWithResp(reqType, opts, nfy)
resp, err := c.doSwrkWithResp(reqType, opts, nfy, nil)
if err != nil {
return err
}
respType := resp.GetType()
if respType != reqType {
return errors.New("unexpected responce")
return errors.New("unexpected CRIU RPC response")
}

return nil
}

func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify) (*rpc.CriuResp, error) {
func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy Notify, features *rpc.CriuFeatures) (*rpc.CriuResp, error) {
var resp *rpc.CriuResp

req := rpc.CriuReq{
Expand All @@ -111,6 +111,10 @@ func (c *Criu) doSwrkWithResp(reqType rpc.CriuReqType, opts *rpc.CriuOpts, nfy N
opts.NotifyScripts = proto.Bool(true)
}

if features != nil {
req.Features = features
}

if c.swrkCmd == nil {
err := c.Prepare()
if err != nil {
Expand Down Expand Up @@ -209,7 +213,7 @@ func (c *Criu) StartPageServer(opts *rpc.CriuOpts) error {

// StartPageServerChld starts the page server and returns PID and port
func (c *Criu) StartPageServerChld(opts *rpc.CriuOpts) (int, int, error) {
resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, opts, nil)
resp, err := c.doSwrkWithResp(rpc.CriuReqType_PAGE_SERVER_CHLD, opts, nil, nil)
if err != nil {
return 0, 0, err
}
Expand All @@ -220,7 +224,7 @@ func (c *Criu) StartPageServerChld(opts *rpc.CriuOpts) (int, int, error) {
// GetCriuVersion executes the VERSION RPC call and returns the version
// as an integer. Major * 10000 + Minor * 100 + SubLevel
func (c *Criu) GetCriuVersion() (int, error) {
resp, err := c.doSwrkWithResp(rpc.CriuReqType_VERSION, nil, nil)
resp, err := c.doSwrkWithResp(rpc.CriuReqType_VERSION, nil, nil, nil)
if err != nil {
return 0, err
}
Expand Down
68 changes: 68 additions & 0 deletions test/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,69 @@ func doDump(c *criu.Criu, pidS string, imgDir string, pre bool, prevImg string)
return nil
}

func featureCheck(c *criu.Criu) error {
features := &rpc.CriuFeatures{}
featuresToCompare := &rpc.CriuFeatures{}
env := os.Getenv("CRIU_FEATURE_MEM_TRACK")
if env != "" {
val, err := strconv.Atoi(env)
if err != nil {
return err
}
features.MemTrack = proto.Bool(val != 0)
featuresToCompare.MemTrack = proto.Bool(val != 0)
}
env = os.Getenv("CRIU_FEATURE_LAZY_PAGES")
if env != "" {
val, err := strconv.Atoi(env)
if err != nil {
return err
}
features.LazyPages = proto.Bool(val != 0)
featuresToCompare.LazyPages = proto.Bool(val != 0)
}
env = os.Getenv("CRIU_FEATURE_PIDFD_STORE")
if env != "" {
val, err := strconv.Atoi(env)
if err != nil {
return err
}
features.PidfdStore = proto.Bool(val != 0)
featuresToCompare.PidfdStore = proto.Bool(val != 0)
}

features, err := c.FeatureCheck(features)
if err != nil {
return err
}

if *features.MemTrack != *featuresToCompare.MemTrack {
return fmt.Errorf(
"Unexpected MemTrack FeatureCheck result %v:%v",
*features.MemTrack,
*featuresToCompare.MemTrack,
)
}

if *features.LazyPages != *featuresToCompare.LazyPages {
return fmt.Errorf(
"Unexpected LazyPages FeatureCheck result %v:%v",
*features.LazyPages,
*featuresToCompare.LazyPages,
)
}

if *features.PidfdStore != *featuresToCompare.PidfdStore {
return fmt.Errorf(
"Unexpected PidfdStore FeatureCheck result %v:%v",
*features.PidfdStore,
*featuresToCompare.PidfdStore,
)
}

return nil
}

// Usage: test $act $pid $images_dir
func main() {
c := criu.MakeCriu()
Expand All @@ -76,6 +139,11 @@ func main() {
if !result {
log.Fatalln("CRIU version to old")
}

if err = featureCheck(c); err != nil {
log.Fatalln(err)
}

act := os.Args[1]
switch act {
case "dump":
Expand Down

0 comments on commit 5b3b8ad

Please sign in to comment.