Merge pull request #37350 from tonistiigi/platform-support

Fix platform struct passing
diff --git a/api/server/router/build/build_routes.go b/api/server/router/build/build_routes.go
index 2d73e9b..071402a 100644
--- a/api/server/router/build/build_routes.go
+++ b/api/server/router/build/build_routes.go
@@ -14,6 +14,7 @@
 	"strings"
 	"sync"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/api/server/httputils"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
@@ -72,11 +73,16 @@
 	options.RemoteContext = r.FormValue("remote")
 	if versions.GreaterThanOrEqualTo(version, "1.32") {
 		apiPlatform := r.FormValue("platform")
-		p := system.ParsePlatform(apiPlatform)
-		if err := system.ValidatePlatform(p); err != nil {
-			return nil, errdefs.InvalidParameter(errors.Errorf("invalid platform: %s", err))
+		if apiPlatform != "" {
+			sp, err := platforms.Parse(apiPlatform)
+			if err != nil {
+				return nil, err
+			}
+			if err := system.ValidatePlatform(sp); err != nil {
+				return nil, err
+			}
+			options.Platform = &sp
 		}
-		options.Platform = p.OS
 	}
 
 	if r.Form.Get("shmsize") != "" {
diff --git a/api/server/router/image/backend.go b/api/server/router/image/backend.go
index 93c47cf..5837f9a 100644
--- a/api/server/router/image/backend.go
+++ b/api/server/router/image/backend.go
@@ -8,6 +8,7 @@
 	"github.com/docker/docker/api/types/filters"
 	"github.com/docker/docker/api/types/image"
 	"github.com/docker/docker/api/types/registry"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 // Backend is all the methods that need to be implemented
@@ -34,7 +35,7 @@
 }
 
 type registryBackend interface {
-	PullImage(ctx context.Context, image, tag, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
+	PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
 	PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
 	SearchRegistryForImages(ctx context.Context, filtersArgs string, term string, limit int, authConfig *types.AuthConfig, metaHeaders map[string][]string) (*registry.SearchResults, error)
 }
diff --git a/api/server/router/image/image_routes.go b/api/server/router/image/image_routes.go
index 8e32d02..85707c0 100644
--- a/api/server/router/image/image_routes.go
+++ b/api/server/router/image/image_routes.go
@@ -4,11 +4,11 @@
 	"context"
 	"encoding/base64"
 	"encoding/json"
-	"fmt"
 	"net/http"
 	"strconv"
 	"strings"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/api/server/httputils"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/filters"
@@ -36,7 +36,7 @@
 		message  = r.Form.Get("message")
 		err      error
 		output   = ioutils.NewWriteFlusher(w)
-		platform = &specs.Platform{}
+		platform *specs.Platform
 	)
 	defer output.Close()
 
@@ -45,9 +45,15 @@
 	version := httputils.VersionFromContext(ctx)
 	if versions.GreaterThanOrEqualTo(version, "1.32") {
 		apiPlatform := r.FormValue("platform")
-		platform = system.ParsePlatform(apiPlatform)
-		if err = system.ValidatePlatform(platform); err != nil {
-			err = fmt.Errorf("invalid platform: %s", err)
+		if apiPlatform != "" {
+			sp, err := platforms.Parse(apiPlatform)
+			if err != nil {
+				return err
+			}
+			if err := system.ValidatePlatform(sp); err != nil {
+				return err
+			}
+			platform = &sp
 		}
 	}
 
@@ -70,13 +76,17 @@
 					authConfig = &types.AuthConfig{}
 				}
 			}
-			err = s.backend.PullImage(ctx, image, tag, platform.OS, metaHeaders, authConfig, output)
+			err = s.backend.PullImage(ctx, image, tag, platform, metaHeaders, authConfig, output)
 		} else { //import
 			src := r.Form.Get("fromSrc")
 			// 'err' MUST NOT be defined within this block, we need any error
 			// generated from the download to be available to the output
 			// stream processing below
-			err = s.backend.ImportImage(src, repo, platform.OS, tag, message, r.Body, output, r.Form["changes"])
+			os := ""
+			if platform != nil {
+				os = platform.OS
+			}
+			err = s.backend.ImportImage(src, repo, os, tag, message, r.Body, output, r.Form["changes"])
 		}
 	}
 	if err != nil {
diff --git a/api/types/backend/build.go b/api/types/backend/build.go
index 31e00ec..1a2e59f 100644
--- a/api/types/backend/build.go
+++ b/api/types/backend/build.go
@@ -5,6 +5,7 @@
 
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/pkg/streamformatter"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 // PullOption defines different modes for accessing images
@@ -40,5 +41,5 @@
 	PullOption PullOption
 	AuthConfig map[string]types.AuthConfig
 	Output     io.Writer
-	OS         string
+	Platform   *specs.Platform
 }
diff --git a/api/types/client.go b/api/types/client.go
index 3df8d23..33bc98e 100644
--- a/api/types/client.go
+++ b/api/types/client.go
@@ -8,6 +8,7 @@
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/filters"
 	"github.com/docker/go-units"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 // CheckpointCreateOptions holds parameters to create a checkpoint from a container
@@ -180,7 +181,7 @@
 	ExtraHosts  []string // List of extra hosts
 	Target      string
 	SessionID   string
-	Platform    string
+	Platform    *specs.Platform
 	// Version specifies the version of the unerlying builder to use
 	Version BuilderVersion
 	// BuildID is an optional identifier that can be passed together with the
diff --git a/builder/builder-next/adapters/containerimage/pull.go b/builder/builder-next/adapters/containerimage/pull.go
index b84d2e8..f76ac5a 100644
--- a/builder/builder-next/adapters/containerimage/pull.go
+++ b/builder/builder-next/adapters/containerimage/pull.go
@@ -113,7 +113,7 @@
 	return img.RawJSON(), nil
 }
 
-func (is *imageSource) ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error) {
+func (is *imageSource) ResolveImageConfig(ctx context.Context, ref string, platform *ocispec.Platform) (digest.Digest, []byte, error) {
 	if preferLocal {
 		dt, err := is.resolveLocal(ref)
 		if err == nil {
@@ -126,7 +126,7 @@
 		dt   []byte
 	}
 	res, err := is.g.Do(ctx, ref, func(ctx context.Context) (interface{}, error) {
-		dgst, dt, err := imageutil.Config(ctx, ref, is.getResolver(ctx), is.ContentStore, "")
+		dgst, dt, err := imageutil.Config(ctx, ref, is.getResolver(ctx), is.ContentStore, platform)
 		if err != nil {
 			return nil, err
 		}
@@ -145,10 +145,16 @@
 		return nil, errors.Errorf("invalid image identifier %v", id)
 	}
 
+	platform := platforms.DefaultSpec()
+	if imageIdentifier.Platform != nil {
+		platform = *imageIdentifier.Platform
+	}
+
 	p := &puller{
 		src:      imageIdentifier,
 		is:       is,
 		resolver: is.getResolver(ctx),
+		platform: platform,
 	}
 	return p, nil
 }
@@ -163,17 +169,20 @@
 	resolveErr       error
 	resolver         remotes.Resolver
 	config           []byte
+	platform         ocispec.Platform
 }
 
-func (p *puller) mainManifestKey(dgst digest.Digest) (digest.Digest, error) {
+func (p *puller) mainManifestKey(dgst digest.Digest, platform ocispec.Platform) (digest.Digest, error) {
 	dt, err := json.Marshal(struct {
-		Digest digest.Digest
-		OS     string
-		Arch   string
+		Digest  digest.Digest
+		OS      string
+		Arch    string
+		Variant string `json:",omitempty"`
 	}{
-		Digest: p.desc.Digest,
-		OS:     runtime.GOOS,
-		Arch:   runtime.GOARCH,
+		Digest:  p.desc.Digest,
+		OS:      platform.OS,
+		Arch:    platform.Architecture,
+		Variant: platform.Variant,
 	})
 	if err != nil {
 		return "", err
@@ -248,7 +257,7 @@
 				return
 			}
 
-			_, dt, err := p.is.ResolveImageConfig(ctx, ref.String())
+			_, dt, err := p.is.ResolveImageConfig(ctx, ref.String(), &p.platform)
 			if err != nil {
 				p.resolveErr = err
 				resolveProgressDone(err)
@@ -266,7 +275,7 @@
 	p.resolveLocal()
 
 	if p.desc.Digest != "" && index == 0 {
-		dgst, err := p.mainManifestKey(p.desc.Digest)
+		dgst, err := p.mainManifestKey(p.desc.Digest, p.platform)
 		if err != nil {
 			return "", false, err
 		}
@@ -282,7 +291,7 @@
 	}
 
 	if p.desc.Digest != "" && index == 0 {
-		dgst, err := p.mainManifestKey(p.desc.Digest)
+		dgst, err := p.mainManifestKey(p.desc.Digest, p.platform)
 		if err != nil {
 			return "", false, err
 		}
diff --git a/builder/builder-next/builder.go b/builder/builder-next/builder.go
index 8c48d9a..5a82cdd 100644
--- a/builder/builder-next/builder.go
+++ b/builder/builder-next/builder.go
@@ -9,6 +9,7 @@
 	"time"
 
 	"github.com/containerd/containerd/content"
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/builder"
@@ -208,6 +209,10 @@
 		frontendAttrs["no-cache"] = ""
 	}
 
+	if opt.Options.Platform != nil {
+		frontendAttrs["platform"] = platforms.Format(*opt.Options.Platform)
+	}
+
 	exporterAttrs := map[string]string{}
 
 	if len(opt.Options.Tags) > 0 {
diff --git a/builder/builder-next/worker/worker.go b/builder/builder-next/worker/worker.go
index 28e1636..29e8095 100644
--- a/builder/builder-next/worker/worker.go
+++ b/builder/builder-next/worker/worker.go
@@ -10,6 +10,7 @@
 	"time"
 
 	"github.com/containerd/containerd/content"
+	"github.com/containerd/containerd/platforms"
 	"github.com/containerd/containerd/rootfs"
 	"github.com/docker/docker/distribution"
 	distmetadata "github.com/docker/docker/distribution/metadata"
@@ -122,6 +123,12 @@
 	return w.Opt.Labels
 }
 
+// Platforms returns one or more platforms supported by the image.
+func (w *Worker) Platforms() []ocispec.Platform {
+	// does not handle lcow
+	return []ocispec.Platform{platforms.DefaultSpec()}
+}
+
 // LoadRef loads a reference by ID
 func (w *Worker) LoadRef(id string) (cache.ImmutableRef, error) {
 	return w.CacheManager.Get(context.TODO(), id)
@@ -129,26 +136,27 @@
 
 // ResolveOp converts a LLB vertex into a LLB operation
 func (w *Worker) ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge) (solver.Op, error) {
-	switch op := v.Sys().(type) {
-	case *pb.Op_Source:
-		return ops.NewSourceOp(v, op, w.SourceManager, w)
-	case *pb.Op_Exec:
-		return ops.NewExecOp(v, op, w.CacheManager, w.MetadataStore, w.Executor, w)
-	case *pb.Op_Build:
-		return ops.NewBuildOp(v, op, s, w)
-	default:
-		return nil, errors.Errorf("could not resolve %v", v)
+	if baseOp, ok := v.Sys().(*pb.Op); ok {
+		switch op := baseOp.Op.(type) {
+		case *pb.Op_Source:
+			return ops.NewSourceOp(v, op, baseOp.Platform, w.SourceManager, w)
+		case *pb.Op_Exec:
+			return ops.NewExecOp(v, op, w.CacheManager, w.MetadataStore, w.Executor, w)
+		case *pb.Op_Build:
+			return ops.NewBuildOp(v, op, s, w)
+		}
 	}
+	return nil, errors.Errorf("could not resolve %v", v)
 }
 
 // ResolveImageConfig returns image config for an image
-func (w *Worker) ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error) {
+func (w *Worker) ResolveImageConfig(ctx context.Context, ref string, platform *ocispec.Platform) (digest.Digest, []byte, error) {
 	// ImageSource is typically source/containerimage
 	resolveImageConfig, ok := w.ImageSource.(resolveImageConfig)
 	if !ok {
 		return "", nil, errors.Errorf("worker %q does not implement ResolveImageConfig", w.ID())
 	}
-	return resolveImageConfig.ResolveImageConfig(ctx, ref)
+	return resolveImageConfig.ResolveImageConfig(ctx, ref, platform)
 }
 
 // Exec executes a process directly on a worker
@@ -319,5 +327,5 @@
 }
 
 type resolveImageConfig interface {
-	ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error)
+	ResolveImageConfig(ctx context.Context, ref string, platform *ocispec.Platform) (digest.Digest, []byte, error)
 }
diff --git a/builder/dockerfile/builder.go b/builder/dockerfile/builder.go
index d5d2de8..b585347 100644
--- a/builder/dockerfile/builder.go
+++ b/builder/dockerfile/builder.go
@@ -104,13 +104,6 @@
 		source = src
 	}
 
-	os := ""
-	apiPlatform := system.ParsePlatform(config.Options.Platform)
-	if apiPlatform.OS != "" {
-		os = apiPlatform.OS
-	}
-	config.Options.Platform = os
-
 	builderOptions := builderOptions{
 		Options:        config.Options,
 		ProgressWriter: config.ProgressWriter,
diff --git a/builder/dockerfile/copy.go b/builder/dockerfile/copy.go
index 43f40b6..7e9dc60 100644
--- a/builder/dockerfile/copy.go
+++ b/builder/dockerfile/copy.go
@@ -24,6 +24,7 @@
 	"github.com/docker/docker/pkg/streamformatter"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/urlutil"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
@@ -72,7 +73,7 @@
 	source      builder.Source
 	pathCache   pathCache
 	download    sourceDownloader
-	platform    string
+	platform    *specs.Platform
 	// for cleanup. TODO: having copier.cleanup() is error prone and hard to
 	// follow. Code calling performCopy should manage the lifecycle of its params.
 	// Copier should take override source as input, not imageMount.
@@ -95,8 +96,14 @@
 	last := len(args) - 1
 
 	// Work in platform-specific filepath semantics
-	inst.dest = fromSlash(args[last], o.platform)
-	separator := string(separator(o.platform))
+	// TODO: This OS switch for paths is NOT correct and should not be supported.
+	// Maintained for backwards compatibility
+	pathOS := runtime.GOOS
+	if o.platform != nil {
+		pathOS = o.platform.OS
+	}
+	inst.dest = fromSlash(args[last], pathOS)
+	separator := string(separator(pathOS))
 	infos, err := o.getCopyInfosForSourcePaths(args[0:last], inst.dest)
 	if err != nil {
 		return inst, errors.Wrapf(err, "%s failed", cmdName)
diff --git a/builder/dockerfile/dispatchers.go b/builder/dockerfile/dispatchers.go
index 4d47c20..1032c6c 100644
--- a/builder/dockerfile/dispatchers.go
+++ b/builder/dockerfile/dispatchers.go
@@ -14,6 +14,7 @@
 	"sort"
 	"strings"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/api"
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/strslice"
@@ -27,6 +28,7 @@
 	"github.com/moby/buildkit/frontend/dockerfile/instructions"
 	"github.com/moby/buildkit/frontend/dockerfile/parser"
 	"github.com/moby/buildkit/frontend/dockerfile/shell"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
@@ -102,7 +104,7 @@
 	copyInstruction.chownStr = c.Chown
 	copyInstruction.allowLocalDecompression = true
 
-	return d.builder.performCopy(d.state, copyInstruction)
+	return d.builder.performCopy(d, copyInstruction)
 }
 
 // COPY foo /path
@@ -126,7 +128,7 @@
 	}
 	copyInstruction.chownStr = c.Chown
 
-	return d.builder.performCopy(d.state, copyInstruction)
+	return d.builder.performCopy(d, copyInstruction)
 }
 
 func (d *dispatchRequest) getImageMount(imageRefOrID string) (*imageMount, error) {
@@ -144,17 +146,32 @@
 		imageRefOrID = stage.Image
 		localOnly = true
 	}
-	return d.builder.imageSources.Get(imageRefOrID, localOnly, d.state.operatingSystem)
+	return d.builder.imageSources.Get(imageRefOrID, localOnly, d.builder.options.Platform)
 }
 
 // FROM [--platform=platform] imagename[:tag | @digest] [AS build-stage-name]
 //
 func initializeStage(d dispatchRequest, cmd *instructions.Stage) error {
 	d.builder.imageProber.Reset()
-	if err := system.ValidatePlatform(&cmd.Platform); err != nil {
-		return err
+
+	var platform *specs.Platform
+	if v := cmd.Platform; v != "" {
+		v, err := d.getExpandedString(d.shlex, v)
+		if err != nil {
+			return errors.Wrapf(err, "failed to process arguments for platform %s", v)
+		}
+
+		p, err := platforms.Parse(v)
+		if err != nil {
+			return errors.Wrapf(err, "failed to parse platform %s", v)
+		}
+		if err := system.ValidatePlatform(p); err != nil {
+			return err
+		}
+		platform = &p
 	}
-	image, err := d.getFromImage(d.shlex, cmd.BaseName, cmd.Platform.OS)
+
+	image, err := d.getFromImage(d.shlex, cmd.BaseName, platform)
 	if err != nil {
 		return err
 	}
@@ -200,82 +217,72 @@
 	return nil
 }
 
-func (d *dispatchRequest) getExpandedImageName(shlex *shell.Lex, name string) (string, error) {
+func (d *dispatchRequest) getExpandedString(shlex *shell.Lex, str string) (string, error) {
 	substitutionArgs := []string{}
 	for key, value := range d.state.buildArgs.GetAllMeta() {
 		substitutionArgs = append(substitutionArgs, key+"="+value)
 	}
 
-	name, err := shlex.ProcessWord(name, substitutionArgs)
+	name, err := shlex.ProcessWord(str, substitutionArgs)
 	if err != nil {
 		return "", err
 	}
 	return name, nil
 }
 
-// getOsFromFlagsAndStage calculates the operating system if we need to pull an image.
-// stagePlatform contains the value supplied by optional `--platform=` on
-// a current FROM statement. b.builder.options.Platform contains the operating
-// system part of the optional flag passed in the API call (or CLI flag
-// through `docker build --platform=...`). Precedence is for an explicit
-// platform indication in the FROM statement.
-func (d *dispatchRequest) getOsFromFlagsAndStage(stageOS string) string {
-	switch {
-	case stageOS != "":
-		return stageOS
-	case d.builder.options.Platform != "":
-		// Note this is API "platform", but by this point, as the daemon is not
-		// multi-arch aware yet, it is guaranteed to only hold the OS part here.
-		return d.builder.options.Platform
-	default:
-		return runtime.GOOS
-	}
-}
-
-func (d *dispatchRequest) getImageOrStage(name string, stageOS string) (builder.Image, error) {
+func (d *dispatchRequest) getImageOrStage(name string, platform *specs.Platform) (builder.Image, error) {
 	var localOnly bool
 	if im, ok := d.stages.getByName(name); ok {
 		name = im.Image
 		localOnly = true
 	}
 
-	os := d.getOsFromFlagsAndStage(stageOS)
+	if platform == nil {
+		platform = d.builder.options.Platform
+	}
 
 	// Windows cannot support a container with no base image unless it is LCOW.
 	if name == api.NoBaseImageSpecifier {
+		p := platforms.DefaultSpec()
+		if platform != nil {
+			p = *platform
+		}
 		imageImage := &image.Image{}
-		imageImage.OS = runtime.GOOS
+		imageImage.OS = p.OS
+
+		// old windows scratch handling
+		// TODO: scratch should not have an os. It should be nil image.
+		// Windows supports scratch. What is not supported is running containers
+		// from it.
 		if runtime.GOOS == "windows" {
-			switch os {
-			case "windows", "":
-				return nil, errors.New("Windows does not support FROM scratch")
-			case "linux":
+			if platform == nil || platform.OS == "linux" {
 				if !system.LCOWSupported() {
 					return nil, errors.New("Linux containers are not supported on this system")
 				}
 				imageImage.OS = "linux"
-			default:
-				return nil, errors.Errorf("operating system %q is not supported", os)
+			} else if platform.OS == "windows" {
+				return nil, errors.New("Windows does not support FROM scratch")
+			} else {
+				return nil, errors.Errorf("platform %s is not supported", platforms.Format(p))
 			}
 		}
 		return builder.Image(imageImage), nil
 	}
-	imageMount, err := d.builder.imageSources.Get(name, localOnly, os)
+	imageMount, err := d.builder.imageSources.Get(name, localOnly, platform)
 	if err != nil {
 		return nil, err
 	}
 	return imageMount.Image(), nil
 }
-func (d *dispatchRequest) getFromImage(shlex *shell.Lex, name string, stageOS string) (builder.Image, error) {
-	name, err := d.getExpandedImageName(shlex, name)
+func (d *dispatchRequest) getFromImage(shlex *shell.Lex, name string, platform *specs.Platform) (builder.Image, error) {
+	name, err := d.getExpandedString(shlex, name)
 	if err != nil {
 		return nil, err
 	}
-	return d.getImageOrStage(name, stageOS)
+	return d.getImageOrStage(name, platform)
 }
 
 func dispatchOnbuild(d dispatchRequest, c *instructions.OnbuildCommand) error {
-
 	d.state.runConfig.OnBuild = append(d.state.runConfig.OnBuild, c.Expression)
 	return d.builder.commit(d.state, "ONBUILD "+c.Expression)
 }
diff --git a/builder/dockerfile/dispatchers_test.go b/builder/dockerfile/dispatchers_test.go
index 36d20a1..047a874 100644
--- a/builder/dockerfile/dispatchers_test.go
+++ b/builder/dockerfile/dispatchers_test.go
@@ -6,6 +6,7 @@
 	"runtime"
 	"testing"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/api/types/container"
@@ -22,15 +23,17 @@
 
 func newBuilderWithMockBackend() *Builder {
 	mockBackend := &MockBackend{}
+	defaultPlatform := platforms.DefaultSpec()
+	opts := &types.ImageBuildOptions{Platform: &defaultPlatform}
 	ctx := context.Background()
 	b := &Builder{
-		options:       &types.ImageBuildOptions{Platform: runtime.GOOS},
+		options:       opts,
 		docker:        mockBackend,
 		Stdout:        new(bytes.Buffer),
 		clientCtx:     ctx,
 		disableCommit: true,
 		imageSources: newImageSources(ctx, builderOptions{
-			Options: &types.ImageBuildOptions{Platform: runtime.GOOS},
+			Options: opts,
 			Backend: mockBackend,
 		}),
 		imageProber:      newImageProber(mockBackend, nil, false),
diff --git a/builder/dockerfile/imagecontext.go b/builder/dockerfile/imagecontext.go
index 53a4b97..08cb396 100644
--- a/builder/dockerfile/imagecontext.go
+++ b/builder/dockerfile/imagecontext.go
@@ -7,11 +7,12 @@
 	"github.com/docker/docker/api/types/backend"
 	"github.com/docker/docker/builder"
 	dockerimage "github.com/docker/docker/image"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 )
 
-type getAndMountFunc func(string, bool, string) (builder.Image, builder.ROLayer, error)
+type getAndMountFunc func(string, bool, *specs.Platform) (builder.Image, builder.ROLayer, error)
 
 // imageSources mounts images and provides a cache for mounted images. It tracks
 // all images so they can be unmounted at the end of the build.
@@ -22,7 +23,7 @@
 }
 
 func newImageSources(ctx context.Context, options builderOptions) *imageSources {
-	getAndMount := func(idOrRef string, localOnly bool, osForPull string) (builder.Image, builder.ROLayer, error) {
+	getAndMount := func(idOrRef string, localOnly bool, platform *specs.Platform) (builder.Image, builder.ROLayer, error) {
 		pullOption := backend.PullOptionNoPull
 		if !localOnly {
 			if options.Options.PullParent {
@@ -35,7 +36,7 @@
 			PullOption: pullOption,
 			AuthConfig: options.Options.AuthConfigs,
 			Output:     options.ProgressWriter.Output,
-			OS:         osForPull,
+			Platform:   platform,
 		})
 	}
 
@@ -45,12 +46,12 @@
 	}
 }
 
-func (m *imageSources) Get(idOrRef string, localOnly bool, osForPull string) (*imageMount, error) {
+func (m *imageSources) Get(idOrRef string, localOnly bool, platform *specs.Platform) (*imageMount, error) {
 	if im, ok := m.byImageID[idOrRef]; ok {
 		return im, nil
 	}
 
-	image, layer, err := m.getImage(idOrRef, localOnly, osForPull)
+	image, layer, err := m.getImage(idOrRef, localOnly, platform)
 	if err != nil {
 		return nil, err
 	}
diff --git a/builder/dockerfile/internals.go b/builder/dockerfile/internals.go
index 88e75a2..5e2c286 100644
--- a/builder/dockerfile/internals.go
+++ b/builder/dockerfile/internals.go
@@ -150,7 +150,8 @@
 	return nil
 }
 
-func (b *Builder) performCopy(state *dispatchState, inst copyInstruction) error {
+func (b *Builder) performCopy(req dispatchRequest, inst copyInstruction) error {
+	state := req.state
 	srcHash := getSourceHashFromInfos(inst.infos)
 
 	var chownComment string
@@ -168,7 +169,7 @@
 		return err
 	}
 
-	imageMount, err := b.imageSources.Get(state.imageID, true, state.operatingSystem)
+	imageMount, err := b.imageSources.Get(state.imageID, true, req.builder.options.Platform)
 	if err != nil {
 		return errors.Wrapf(err, "failed to get destination image %q", state.imageID)
 	}
@@ -456,7 +457,7 @@
 	// is too small for builder scenarios where many users are
 	// using RUN statements to install large amounts of data.
 	// Use 127GB as that's the default size of a VHD in Hyper-V.
-	if runtime.GOOS == "windows" && options.Platform == "windows" {
+	if runtime.GOOS == "windows" && options.Platform != nil && options.Platform.OS == "windows" {
 		hc.StorageOpt = make(map[string]string)
 		hc.StorageOpt["size"] = "127GB"
 	}
diff --git a/client/image_build.go b/client/image_build.go
index dff19b9..e501317 100644
--- a/client/image_build.go
+++ b/client/image_build.go
@@ -8,8 +8,8 @@
 	"net/http"
 	"net/url"
 	"strconv"
-	"strings"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types/container"
 )
@@ -30,11 +30,11 @@
 	}
 	headers.Add("X-Registry-Config", base64.URLEncoding.EncodeToString(buf))
 
-	if options.Platform != "" {
+	if options.Platform != nil {
 		if err := cli.NewVersionError("1.32", "platform"); err != nil {
 			return types.ImageBuildResponse{}, err
 		}
-		query.Set("platform", options.Platform)
+		query.Set("platform", platforms.Format(*options.Platform))
 	}
 	headers.Set("Content-Type", "application/x-tar")
 
@@ -130,8 +130,8 @@
 	if options.SessionID != "" {
 		query.Set("session", options.SessionID)
 	}
-	if options.Platform != "" {
-		query.Set("platform", strings.ToLower(options.Platform))
+	if options.Platform != nil {
+		query.Set("platform", platforms.Format(*options.Platform))
 	}
 	if options.BuildID != "" {
 		query.Set("buildid", options.BuildID)
diff --git a/daemon/cluster/executor/backend.go b/daemon/cluster/executor/backend.go
index 1f2312a..cfbc86c 100644
--- a/daemon/cluster/executor/backend.go
+++ b/daemon/cluster/executor/backend.go
@@ -23,6 +23,7 @@
 	"github.com/docker/libnetwork/cluster"
 	networktypes "github.com/docker/libnetwork/types"
 	"github.com/docker/swarmkit/agent/exec"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 // Backend defines the executor component for a swarm agent.
@@ -69,7 +70,7 @@
 
 // ImageBackend is used by an executor to perform image operations
 type ImageBackend interface {
-	PullImage(ctx context.Context, image, tag, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
+	PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
 	GetRepository(context.Context, reference.Named, *types.AuthConfig) (distribution.Repository, bool, error)
 	LookupImage(name string) (*types.ImageInspect, error)
 }
diff --git a/daemon/cluster/executor/container/adapter.go b/daemon/cluster/executor/container/adapter.go
index fdf1ee2..6b222f2 100644
--- a/daemon/cluster/executor/container/adapter.go
+++ b/daemon/cluster/executor/container/adapter.go
@@ -8,7 +8,6 @@
 	"fmt"
 	"io"
 	"os"
-	"runtime"
 	"strings"
 	"syscall"
 	"time"
@@ -97,8 +96,7 @@
 	go func() {
 		// TODO @jhowardmsft LCOW Support: This will need revisiting as
 		// the stack is built up to include LCOW support for swarm.
-		platform := runtime.GOOS
-		err := c.imageBackend.PullImage(ctx, c.container.image(), "", platform, metaHeaders, authConfig, pw)
+		err := c.imageBackend.PullImage(ctx, c.container.image(), "", nil, metaHeaders, authConfig, pw)
 		pw.CloseWithError(err)
 	}()
 
diff --git a/daemon/images/image_builder.go b/daemon/images/image_builder.go
index ca7d0fd..cdf951c 100644
--- a/daemon/images/image_builder.go
+++ b/daemon/images/image_builder.go
@@ -3,6 +3,7 @@
 import (
 	"context"
 	"io"
+	"runtime"
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api/types"
@@ -14,6 +15,7 @@
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/registry"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
@@ -137,7 +139,7 @@
 }
 
 // TODO: could this use the regular daemon PullImage ?
-func (i *ImageService) pullForBuilder(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer, os string) (*image.Image, error) {
+func (i *ImageService) pullForBuilder(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer, platform *specs.Platform) (*image.Image, error) {
 	ref, err := reference.ParseNormalizedNamed(name)
 	if err != nil {
 		return nil, err
@@ -156,7 +158,7 @@
 		pullRegistryAuth = &resolvedConfig
 	}
 
-	if err := i.pullImageWithReference(ctx, ref, os, nil, pullRegistryAuth, output); err != nil {
+	if err := i.pullImageWithReference(ctx, ref, platform, nil, pullRegistryAuth, output); err != nil {
 		return nil, err
 	}
 	return i.GetImage(name)
@@ -166,11 +168,15 @@
 // Every call to GetImageAndReleasableLayer MUST call releasableLayer.Release() to prevent
 // leaking of layers.
 func (i *ImageService) GetImageAndReleasableLayer(ctx context.Context, refOrID string, opts backend.GetImageAndLayerOptions) (builder.Image, builder.ROLayer, error) {
-	if refOrID == "" {
-		if !system.IsOSSupported(opts.OS) {
+	if refOrID == "" { // ie FROM scratch
+		os := runtime.GOOS
+		if opts.Platform != nil {
+			os = opts.Platform.OS
+		}
+		if !system.IsOSSupported(os) {
 			return nil, nil, system.ErrNotSupportedOperatingSystem
 		}
-		layer, err := newROLayerForImage(nil, i.layerStores[opts.OS])
+		layer, err := newROLayerForImage(nil, i.layerStores[os])
 		return nil, layer, err
 	}
 
@@ -189,7 +195,7 @@
 		}
 	}
 
-	image, err := i.pullForBuilder(ctx, refOrID, opts.AuthConfig, opts.Output, opts.OS)
+	image, err := i.pullForBuilder(ctx, refOrID, opts.AuthConfig, opts.Output, opts.Platform)
 	if err != nil {
 		return nil, nil, err
 	}
diff --git a/daemon/images/image_pull.go b/daemon/images/image_pull.go
index 238c38b..3e6b433 100644
--- a/daemon/images/image_pull.go
+++ b/daemon/images/image_pull.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"io"
-	"runtime"
 	"strings"
 	"time"
 
@@ -16,11 +15,12 @@
 	"github.com/docker/docker/pkg/progress"
 	"github.com/docker/docker/registry"
 	"github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 // PullImage initiates a pull operation. image is the repository name to pull, and
 // tag may be either empty, or indicate a specific tag to pull.
-func (i *ImageService) PullImage(ctx context.Context, image, tag, os string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
+func (i *ImageService) PullImage(ctx context.Context, image, tag string, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
 	start := time.Now()
 	// Special case: "pull -a" may send an image name with a
 	// trailing :. This is ugly, but let's not break API
@@ -46,12 +46,12 @@
 		}
 	}
 
-	err = i.pullImageWithReference(ctx, ref, os, metaHeaders, authConfig, outStream)
+	err = i.pullImageWithReference(ctx, ref, platform, metaHeaders, authConfig, outStream)
 	imageActions.WithValues("pull").UpdateSince(start)
 	return err
 }
 
-func (i *ImageService) pullImageWithReference(ctx context.Context, ref reference.Named, os string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
+func (i *ImageService) pullImageWithReference(ctx context.Context, ref reference.Named, platform *specs.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
 	// Include a buffer so that slow client connections don't affect
 	// transfer performance.
 	progressChan := make(chan progress.Progress, 100)
@@ -65,11 +65,6 @@
 		close(writesDone)
 	}()
 
-	// Default to the host OS platform in case it hasn't been populated with an explicit value.
-	if os == "" {
-		os = runtime.GOOS
-	}
-
 	imagePullConfig := &distribution.ImagePullConfig{
 		Config: distribution.Config{
 			MetaHeaders:      metaHeaders,
@@ -83,7 +78,7 @@
 		},
 		DownloadManager: i.downloadManager,
 		Schema2Types:    distribution.ImageTypes,
-		OS:              os,
+		Platform:        platform,
 	}
 
 	err := distribution.Pull(ctx, ref, imagePullConfig)
diff --git a/distribution/config.go b/distribution/config.go
index 55f1f8c..438051c 100644
--- a/distribution/config.go
+++ b/distribution/config.go
@@ -60,9 +60,8 @@
 	// Schema2Types is the valid schema2 configuration types allowed
 	// by the pull operation.
 	Schema2Types []string
-	// OS is the requested operating system of the image being pulled to ensure it can be validated
-	// when the host OS supports multiple image operating systems.
-	OS string
+	// Platform is the requested platform of the image being pulled
+	Platform *specs.Platform
 }
 
 // ImagePushConfig stores push configuration.
@@ -171,7 +170,7 @@
 	if !system.IsOSSupported(os) {
 		return nil, system.ErrNotSupportedOperatingSystem
 	}
-	return &specs.Platform{OS: os, OSVersion: unmarshalledConfig.OSVersion}, nil
+	return &specs.Platform{OS: os, Architecture: unmarshalledConfig.Architecture, OSVersion: unmarshalledConfig.OSVersion}, nil
 }
 
 type storeLayerProvider struct {
diff --git a/distribution/pull.go b/distribution/pull.go
index 0240eb0..5de73ae 100644
--- a/distribution/pull.go
+++ b/distribution/pull.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"fmt"
-	"runtime"
 
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/api"
@@ -12,6 +11,7 @@
 	refstore "github.com/docker/docker/reference"
 	"github.com/docker/docker/registry"
 	"github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 )
@@ -21,7 +21,7 @@
 	// Pull tries to pull the image referenced by `tag`
 	// Pull returns an error if any, as well as a boolean that determines whether to retry Pull on the next configured endpoint.
 	//
-	Pull(ctx context.Context, ref reference.Named, os string) error
+	Pull(ctx context.Context, ref reference.Named, platform *specs.Platform) error
 }
 
 // newPuller returns a Puller interface that will pull from either a v1 or v2
@@ -115,12 +115,7 @@
 			continue
 		}
 
-		// Make sure we default the OS if it hasn't been supplied
-		if imagePullConfig.OS == "" {
-			imagePullConfig.OS = runtime.GOOS
-		}
-
-		if err := puller.Pull(ctx, ref, imagePullConfig.OS); err != nil {
+		if err := puller.Pull(ctx, ref, imagePullConfig.Platform); err != nil {
 			// Was this pull cancelled? If so, don't try to fall
 			// back.
 			fallback := false
diff --git a/distribution/pull_v1.go b/distribution/pull_v1.go
index c26d881..c2c897d 100644
--- a/distribution/pull_v1.go
+++ b/distribution/pull_v1.go
@@ -25,6 +25,7 @@
 	"github.com/docker/docker/pkg/progress"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/registry"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/sirupsen/logrus"
 )
 
@@ -36,7 +37,7 @@
 	session     *registry.Session
 }
 
-func (p *v1Puller) Pull(ctx context.Context, ref reference.Named, os string) error {
+func (p *v1Puller) Pull(ctx context.Context, ref reference.Named, _ *specs.Platform) error {
 	if _, isCanonical := ref.(reference.Canonical); isCanonical {
 		// Allowing fallback, because HTTPS v1 is before HTTP v2
 		return fallbackError{err: ErrNoSupport{Err: errors.New("Cannot pull by digest with v1 registry")}}
diff --git a/distribution/pull_v2.go b/distribution/pull_v2.go
index 60a894b..8f05cfa 100644
--- a/distribution/pull_v2.go
+++ b/distribution/pull_v2.go
@@ -11,6 +11,7 @@
 	"runtime"
 	"strings"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/manifest/manifestlist"
 	"github.com/docker/distribution/manifest/schema1"
@@ -63,7 +64,7 @@
 	confirmedV2 bool
 }
 
-func (p *v2Puller) Pull(ctx context.Context, ref reference.Named, os string) (err error) {
+func (p *v2Puller) Pull(ctx context.Context, ref reference.Named, platform *specs.Platform) (err error) {
 	// TODO(tiborvass): was ReceiveTimeout
 	p.repo, p.confirmedV2, err = NewV2Repository(ctx, p.repoInfo, p.endpoint, p.config.MetaHeaders, p.config.AuthConfig, "pull")
 	if err != nil {
@@ -71,7 +72,7 @@
 		return err
 	}
 
-	if err = p.pullV2Repository(ctx, ref, os); err != nil {
+	if err = p.pullV2Repository(ctx, ref, platform); err != nil {
 		if _, ok := err.(fallbackError); ok {
 			return err
 		}
@@ -86,10 +87,10 @@
 	return err
 }
 
-func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named, os string) (err error) {
+func (p *v2Puller) pullV2Repository(ctx context.Context, ref reference.Named, platform *specs.Platform) (err error) {
 	var layersDownloaded bool
 	if !reference.IsNameOnly(ref) {
-		layersDownloaded, err = p.pullV2Tag(ctx, ref, os)
+		layersDownloaded, err = p.pullV2Tag(ctx, ref, platform)
 		if err != nil {
 			return err
 		}
@@ -111,7 +112,7 @@
 			if err != nil {
 				return err
 			}
-			pulledNew, err := p.pullV2Tag(ctx, tagRef, os)
+			pulledNew, err := p.pullV2Tag(ctx, tagRef, platform)
 			if err != nil {
 				// Since this is the pull-all-tags case, don't
 				// allow an error pulling a particular tag to
@@ -327,7 +328,7 @@
 	ld.V2MetadataService.Add(diffID, metadata.V2Metadata{Digest: ld.digest, SourceRepository: ld.repoInfo.Name.Name()})
 }
 
-func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named, os string) (tagUpdated bool, err error) {
+func (p *v2Puller) pullV2Tag(ctx context.Context, ref reference.Named, platform *specs.Platform) (tagUpdated bool, err error) {
 	manSvc, err := p.repo.Manifests(ctx)
 	if err != nil {
 		return false, err
@@ -391,17 +392,17 @@
 		if p.config.RequireSchema2 {
 			return false, fmt.Errorf("invalid manifest: not schema2")
 		}
-		id, manifestDigest, err = p.pullSchema1(ctx, ref, v, os)
+		id, manifestDigest, err = p.pullSchema1(ctx, ref, v, platform)
 		if err != nil {
 			return false, err
 		}
 	case *schema2.DeserializedManifest:
-		id, manifestDigest, err = p.pullSchema2(ctx, ref, v, os)
+		id, manifestDigest, err = p.pullSchema2(ctx, ref, v, platform)
 		if err != nil {
 			return false, err
 		}
 	case *manifestlist.DeserializedManifestList:
-		id, manifestDigest, err = p.pullManifestList(ctx, ref, v, os)
+		id, manifestDigest, err = p.pullManifestList(ctx, ref, v, platform)
 		if err != nil {
 			return false, err
 		}
@@ -437,7 +438,7 @@
 	return true, nil
 }
 
-func (p *v2Puller) pullSchema1(ctx context.Context, ref reference.Reference, unverifiedManifest *schema1.SignedManifest, requestedOS string) (id digest.Digest, manifestDigest digest.Digest, err error) {
+func (p *v2Puller) pullSchema1(ctx context.Context, ref reference.Reference, unverifiedManifest *schema1.SignedManifest, platform *specs.Platform) (id digest.Digest, manifestDigest digest.Digest, err error) {
 	var verifiedManifest *schema1.Manifest
 	verifiedManifest, err = verifySchema1Manifest(unverifiedManifest, ref)
 	if err != nil {
@@ -509,6 +510,17 @@
 		}
 	}
 
+	// In the situation that the API call didn't specify an OS explicitly, but
+	// we support the operating system, switch to that operating system.
+	// eg FROM supertest2014/nyan with no platform specifier, and docker build
+	// with no --platform= flag under LCOW.
+	requestedOS := ""
+	if platform != nil {
+		requestedOS = platform.OS
+	} else if system.IsOSSupported(configOS) {
+		requestedOS = configOS
+	}
+
 	// Early bath if the requested OS doesn't match that of the configuration.
 	// This avoids doing the download, only to potentially fail later.
 	if !strings.EqualFold(configOS, requestedOS) {
@@ -536,7 +548,7 @@
 	return imageID, manifestDigest, nil
 }
 
-func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *schema2.DeserializedManifest, requestedOS string) (id digest.Digest, manifestDigest digest.Digest, err error) {
+func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *schema2.DeserializedManifest, platform *specs.Platform) (id digest.Digest, manifestDigest digest.Digest, err error) {
 	manifestDigest, err = schema2ManifestDigest(ref, mfst)
 	if err != nil {
 		return "", "", err
@@ -592,6 +604,11 @@
 		configPlatform   *specs.Platform // for LCOW when registering downloaded layers
 	)
 
+	layerStoreOS := runtime.GOOS
+	if platform != nil {
+		layerStoreOS = platform.OS
+	}
+
 	// https://github.com/docker/docker/issues/24766 - Err on the side of caution,
 	// explicitly blocking images intended for linux from the Windows daemon. On
 	// Windows, we do this before the attempt to download, effectively serialising
@@ -615,11 +632,13 @@
 		if len(descriptors) != len(configRootFS.DiffIDs) {
 			return "", "", errRootFSMismatch
 		}
-
-		// Early bath if the requested OS doesn't match that of the configuration.
-		// This avoids doing the download, only to potentially fail later.
-		if !strings.EqualFold(configPlatform.OS, requestedOS) {
-			return "", "", fmt.Errorf("cannot download image with operating system %q when requesting %q", configPlatform.OS, requestedOS)
+		if platform == nil {
+			// Early bath if the requested OS doesn't match that of the configuration.
+			// This avoids doing the download, only to potentially fail later.
+			if !system.IsOSSupported(configPlatform.OS) {
+				return "", "", fmt.Errorf("cannot download image with operating system %q when requesting %q", configPlatform.OS, layerStoreOS)
+			}
+			layerStoreOS = configPlatform.OS
 		}
 
 		// Populate diff ids in descriptors to avoid downloading foreign layers
@@ -636,7 +655,7 @@
 				rootFS image.RootFS
 			)
 			downloadRootFS := *image.NewRootFS()
-			rootFS, release, err = p.config.DownloadManager.Download(ctx, downloadRootFS, requestedOS, descriptors, p.config.ProgressOutput)
+			rootFS, release, err = p.config.DownloadManager.Download(ctx, downloadRootFS, layerStoreOS, descriptors, p.config.ProgressOutput)
 			if err != nil {
 				// Intentionally do not cancel the config download here
 				// as the error from config download (if there is one)
@@ -722,18 +741,22 @@
 
 // pullManifestList handles "manifest lists" which point to various
 // platform-specific manifests.
-func (p *v2Puller) pullManifestList(ctx context.Context, ref reference.Named, mfstList *manifestlist.DeserializedManifestList, os string) (id digest.Digest, manifestListDigest digest.Digest, err error) {
+func (p *v2Puller) pullManifestList(ctx context.Context, ref reference.Named, mfstList *manifestlist.DeserializedManifestList, pp *specs.Platform) (id digest.Digest, manifestListDigest digest.Digest, err error) {
 	manifestListDigest, err = schema2ManifestDigest(ref, mfstList)
 	if err != nil {
 		return "", "", err
 	}
 
-	logrus.Debugf("%s resolved to a manifestList object with %d entries; looking for a %s/%s match", ref, len(mfstList.Manifests), os, runtime.GOARCH)
+	var platform specs.Platform
+	if pp != nil {
+		platform = *pp
+	}
+	logrus.Debugf("%s resolved to a manifestList object with %d entries; looking for a %s/%s match", ref, len(mfstList.Manifests), platforms.Format(platform), runtime.GOARCH)
 
-	manifestMatches := filterManifests(mfstList.Manifests, os)
+	manifestMatches := filterManifests(mfstList.Manifests, platform)
 
 	if len(manifestMatches) == 0 {
-		errMsg := fmt.Sprintf("no matching manifest for %s/%s in the manifest list entries", os, runtime.GOARCH)
+		errMsg := fmt.Sprintf("no matching manifest for %s in the manifest list entries", platforms.Format(platform))
 		logrus.Debugf(errMsg)
 		return "", "", errors.New(errMsg)
 	}
@@ -764,12 +787,14 @@
 
 	switch v := manifest.(type) {
 	case *schema1.SignedManifest:
-		id, _, err = p.pullSchema1(ctx, manifestRef, v, os)
+		platform := toOCIPlatform(manifestMatches[0].Platform)
+		id, _, err = p.pullSchema1(ctx, manifestRef, v, &platform)
 		if err != nil {
 			return "", "", err
 		}
 	case *schema2.DeserializedManifest:
-		id, _, err = p.pullSchema2(ctx, manifestRef, v, os)
+		platform := toOCIPlatform(manifestMatches[0].Platform)
+		id, _, err = p.pullSchema2(ctx, manifestRef, v, &platform)
 		if err != nil {
 			return "", "", err
 		}
@@ -939,3 +964,13 @@
 func createDownloadFile() (*os.File, error) {
 	return ioutil.TempFile("", "GetImageBlob")
 }
+
+func toOCIPlatform(p manifestlist.PlatformSpec) specs.Platform {
+	return specs.Platform{
+		OS:           p.OS,
+		Architecture: p.Architecture,
+		Variant:      p.Variant,
+		OSFeatures:   p.OSFeatures,
+		OSVersion:    p.OSVersion,
+	}
+}
diff --git a/distribution/pull_v2_unix.go b/distribution/pull_v2_unix.go
index 0be8a03..adbaf41 100644
--- a/distribution/pull_v2_unix.go
+++ b/distribution/pull_v2_unix.go
@@ -4,10 +4,11 @@
 
 import (
 	"context"
-	"runtime"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/manifest/manifestlist"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/sirupsen/logrus"
 )
 
@@ -16,15 +17,28 @@
 	return blobs.Open(ctx, ld.digest)
 }
 
-func filterManifests(manifests []manifestlist.ManifestDescriptor, os string) []manifestlist.ManifestDescriptor {
+func filterManifests(manifests []manifestlist.ManifestDescriptor, p specs.Platform) []manifestlist.ManifestDescriptor {
+	p = platforms.Normalize(withDefault(p))
+	m := platforms.NewMatcher(p)
 	var matches []manifestlist.ManifestDescriptor
-	for _, manifestDescriptor := range manifests {
-		if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == os {
-			matches = append(matches, manifestDescriptor)
-
-			logrus.Debugf("found match for %s/%s with media type %s, digest %s", os, runtime.GOARCH, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
+	for _, desc := range manifests {
+		if m.Match(toOCIPlatform(desc.Platform)) {
+			matches = append(matches, desc)
+			logrus.Debugf("found match for %s with media type %s, digest %s", platforms.Format(p), desc.MediaType, desc.Digest.String())
 		}
 	}
+
+	// deprecated: backwards compatibility with older versions that didn't compare variant
+	if len(matches) == 0 && p.Architecture == "arm" {
+		p = platforms.Normalize(p)
+		for _, desc := range manifests {
+			if desc.Platform.OS == p.OS && desc.Platform.Architecture == p.Architecture {
+				matches = append(matches, desc)
+				logrus.Debugf("found deprecated partial match for %s with media type %s, digest %s", platforms.Format(p), desc.MediaType, desc.Digest.String())
+			}
+		}
+	}
+
 	return matches
 }
 
@@ -32,3 +46,15 @@
 func checkImageCompatibility(imageOS, imageOSVersion string) error {
 	return nil
 }
+
+func withDefault(p specs.Platform) specs.Platform {
+	def := platforms.DefaultSpec()
+	if p.OS == "" {
+		p.OS = def.OS
+	}
+	if p.Architecture == "" {
+		p.Architecture = def.Architecture
+		p.Variant = def.Variant
+	}
+	return p
+}
diff --git a/distribution/pull_v2_windows.go b/distribution/pull_v2_windows.go
index 432a361..3c96458 100644
--- a/distribution/pull_v2_windows.go
+++ b/distribution/pull_v2_windows.go
@@ -16,6 +16,7 @@
 	"github.com/docker/distribution/manifest/schema2"
 	"github.com/docker/distribution/registry/client/transport"
 	"github.com/docker/docker/pkg/system"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/sirupsen/logrus"
 )
 
@@ -62,24 +63,27 @@
 	return rsc, err
 }
 
-func filterManifests(manifests []manifestlist.ManifestDescriptor, os string) []manifestlist.ManifestDescriptor {
-	osVersion := ""
-	if os == "windows" {
-		version := system.GetOSVersion()
-		osVersion = fmt.Sprintf("%d.%d.%d", version.MajorVersion, version.MinorVersion, version.Build)
-		logrus.Debugf("will prefer entries with version %s", osVersion)
-	}
+func filterManifests(manifests []manifestlist.ManifestDescriptor, p specs.Platform) []manifestlist.ManifestDescriptor {
+	version := system.GetOSVersion()
+	osVersion := fmt.Sprintf("%d.%d.%d", version.MajorVersion, version.MinorVersion, version.Build)
+	logrus.Debugf("will prefer Windows entries with version %s", osVersion)
 
 	var matches []manifestlist.ManifestDescriptor
+	foundWindowsMatch := false
 	for _, manifestDescriptor := range manifests {
-		if manifestDescriptor.Platform.Architecture == runtime.GOARCH && manifestDescriptor.Platform.OS == os {
+		if (manifestDescriptor.Platform.Architecture == runtime.GOARCH) &&
+			((p.OS != "" && manifestDescriptor.Platform.OS == p.OS) || // Explicit user request for an OS we know we support
+				(p.OS == "" && system.IsOSSupported(manifestDescriptor.Platform.OS))) { // No user requested OS, but one we can support
 			matches = append(matches, manifestDescriptor)
-			logrus.Debugf("found match for %s/%s %s with media type %s, digest %s", os, runtime.GOARCH, manifestDescriptor.Platform.OSVersion, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
+			logrus.Debugf("found match %s/%s %s with media type %s, digest %s", manifestDescriptor.Platform.OS, runtime.GOARCH, manifestDescriptor.Platform.OSVersion, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
+			if strings.EqualFold("windows", manifestDescriptor.Platform.OS) {
+				foundWindowsMatch = true
+			}
 		} else {
-			logrus.Debugf("ignoring %s/%s %s with media type %s, digest %s", os, runtime.GOARCH, manifestDescriptor.Platform.OSVersion, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
+			logrus.Debugf("ignoring %s/%s %s with media type %s, digest %s", manifestDescriptor.Platform.OS, manifestDescriptor.Platform.Architecture, manifestDescriptor.Platform.OSVersion, manifestDescriptor.MediaType, manifestDescriptor.Digest.String())
 		}
 	}
-	if os == "windows" {
+	if foundWindowsMatch {
 		sort.Stable(manifestsByVersion{osVersion, matches})
 	}
 	return matches
diff --git a/distribution/registry_unit_test.go b/distribution/registry_unit_test.go
index 5ae529d..3651c46 100644
--- a/distribution/registry_unit_test.go
+++ b/distribution/registry_unit_test.go
@@ -5,7 +5,6 @@
 	"net/http"
 	"net/http/httptest"
 	"net/url"
-	"runtime"
 	"strings"
 	"testing"
 
@@ -84,7 +83,7 @@
 	logrus.Debug("About to pull")
 	// We expect it to fail, since we haven't mock'd the full registry exchange in our handler above
 	tag, _ := reference.WithTag(n, "tag_goes_here")
-	_ = p.pullV2Repository(ctx, tag, runtime.GOOS)
+	_ = p.pullV2Repository(ctx, tag, nil)
 }
 
 func TestTokenPassThru(t *testing.T) {
diff --git a/image/store.go b/image/store.go
index 9fd7d7d..1a8a8a2 100644
--- a/image/store.go
+++ b/image/store.go
@@ -76,7 +76,8 @@
 		var l layer.Layer
 		if chainID := img.RootFS.ChainID(); chainID != "" {
 			if !system.IsOSSupported(img.OperatingSystem()) {
-				return system.ErrNotSupportedOperatingSystem
+				logrus.Errorf("not restoring image with unsupported operating system %v, %v, %s", dgst, chainID, img.OperatingSystem())
+				return nil
 			}
 			l, err = is.lss[img.OperatingSystem()].Get(chainID)
 			if err != nil {
diff --git a/image/tarexport/load.go b/image/tarexport/load.go
index c89dd08..7862143 100644
--- a/image/tarexport/load.go
+++ b/image/tarexport/load.go
@@ -11,6 +11,7 @@
 	"reflect"
 	"runtime"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/distribution"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/image"
@@ -421,9 +422,11 @@
 	if runtime.GOOS != "windows" && imageOS == "windows" {
 		return fmt.Errorf("cannot load %s image on %s", imageOS, runtime.GOOS)
 	}
-	// Finally, check the image OS is supported for the platform.
-	if err := system.ValidatePlatform(system.ParsePlatform(imageOS)); err != nil {
-		return fmt.Errorf("cannot load %s image on %s: %s", imageOS, runtime.GOOS, err)
+
+	p, err := platforms.Parse(imageOS)
+	if err != nil {
+		return err
 	}
-	return nil
+
+	return system.ValidatePlatform(p)
 }
diff --git a/pkg/system/lcow.go b/pkg/system/lcow.go
index 5c3fbfe..5be3e21 100644
--- a/pkg/system/lcow.go
+++ b/pkg/system/lcow.go
@@ -1,69 +1,32 @@
 package system // import "github.com/docker/docker/pkg/system"
 
 import (
-	"fmt"
 	"runtime"
 	"strings"
 
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
+	"github.com/pkg/errors"
 )
 
-// ValidatePlatform determines if a platform structure is valid.
-// TODO This is a temporary function - can be replaced by parsing from
-// https://github.com/containerd/containerd/pull/1403/files at a later date.
-// @jhowardmsft
-func ValidatePlatform(platform *specs.Platform) error {
-	platform.Architecture = strings.ToLower(platform.Architecture)
-	platform.OS = strings.ToLower(platform.OS)
-	// Based on https://github.com/moby/moby/pull/34642#issuecomment-330375350, do
-	// not support anything except operating system.
-	if platform.Architecture != "" {
-		return fmt.Errorf("invalid platform architecture %q", platform.Architecture)
-	}
-	if platform.OS != "" {
-		if !(platform.OS == runtime.GOOS || (LCOWSupported() && platform.OS == "linux")) {
-			return fmt.Errorf("invalid platform os %q", platform.OS)
-		}
-	}
-	if len(platform.OSFeatures) != 0 {
-		return fmt.Errorf("invalid platform osfeatures %q", platform.OSFeatures)
-	}
-	if platform.OSVersion != "" {
-		return fmt.Errorf("invalid platform osversion %q", platform.OSVersion)
-	}
-	if platform.Variant != "" {
-		return fmt.Errorf("invalid platform variant %q", platform.Variant)
-	}
-	return nil
-}
-
-// ParsePlatform parses a platform string in the format os[/arch[/variant]
-// into an OCI image-spec platform structure.
-// TODO This is a temporary function - can be replaced by parsing from
-// https://github.com/containerd/containerd/pull/1403/files at a later date.
-// @jhowardmsft
-func ParsePlatform(in string) *specs.Platform {
-	p := &specs.Platform{}
-	elements := strings.SplitN(strings.ToLower(in), "/", 3)
-	if len(elements) == 3 {
-		p.Variant = elements[2]
-	}
-	if len(elements) >= 2 {
-		p.Architecture = elements[1]
-	}
-	if len(elements) >= 1 {
-		p.OS = elements[0]
-	}
-	return p
-}
-
 // IsOSSupported determines if an operating system is supported by the host
 func IsOSSupported(os string) bool {
-	if runtime.GOOS == os {
+	if strings.EqualFold(runtime.GOOS, os) {
 		return true
 	}
-	if LCOWSupported() && os == "linux" {
+	if LCOWSupported() && strings.EqualFold(os, "linux") {
 		return true
 	}
 	return false
 }
+
+// ValidatePlatform determines if a platform structure is valid.
+// TODO This is a temporary windows-only function, should be replaced by
+// comparison of worker capabilities
+func ValidatePlatform(platform specs.Platform) error {
+	if runtime.GOOS == "windows" {
+		if !(platform.OS == runtime.GOOS || (LCOWSupported() && platform.OS == "linux")) {
+			return errors.Errorf("unsupported os %s", platform.OS)
+		}
+	}
+	return nil
+}
diff --git a/vendor.conf b/vendor.conf
index 2699a9d..cd059b7 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -26,7 +26,7 @@
 golang.org/x/sync fd80eb99c8f653c847d294a001bdf2a3a6f768f5
 
 # buildkit
-github.com/moby/buildkit dbf67a691ce77023a0a5ce9b005298631f8bbb4e
+github.com/moby/buildkit cce2080ddbe4698912f2290892b247c83627efa8
 github.com/tonistiigi/fsutil 8abad97ee3969cdf5e9c367f46adba2c212b3ddb
 github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746
 github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7
diff --git a/vendor/github.com/moby/buildkit/api/services/control/control.pb.go b/vendor/github.com/moby/buildkit/api/services/control/control.pb.go
index e92bd7f..5feffaf 100644
--- a/vendor/github.com/moby/buildkit/api/services/control/control.pb.go
+++ b/vendor/github.com/moby/buildkit/api/services/control/control.pb.go
@@ -542,8 +542,9 @@
 }
 
 type WorkerRecord struct {
-	ID     string            `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
-	Labels map[string]string `protobuf:"bytes,2,rep,name=Labels" json:"Labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	ID        string            `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
+	Labels    map[string]string `protobuf:"bytes,2,rep,name=Labels" json:"Labels,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	Platforms []pb.Platform     `protobuf:"bytes,3,rep,name=platforms" json:"platforms"`
 }
 
 func (m *WorkerRecord) Reset()                    { *m = WorkerRecord{} }
@@ -565,6 +566,13 @@
 	return nil
 }
 
+func (m *WorkerRecord) GetPlatforms() []pb.Platform {
+	if m != nil {
+		return m.Platforms
+	}
+	return nil
+}
+
 func init() {
 	proto.RegisterType((*PruneRequest)(nil), "moby.buildkit.v1.PruneRequest")
 	proto.RegisterType((*DiskUsageRequest)(nil), "moby.buildkit.v1.DiskUsageRequest")
@@ -1650,6 +1658,18 @@
 			i += copy(dAtA[i:], v)
 		}
 	}
+	if len(m.Platforms) > 0 {
+		for _, msg := range m.Platforms {
+			dAtA[i] = 0x1a
+			i++
+			i = encodeVarintControl(dAtA, i, uint64(msg.Size()))
+			n, err := msg.MarshalTo(dAtA[i:])
+			if err != nil {
+				return 0, err
+			}
+			i += n
+		}
+	}
 	return i, nil
 }
 
@@ -1979,6 +1999,12 @@
 			n += mapEntrySize + 1 + sovControl(uint64(mapEntrySize))
 		}
 	}
+	if len(m.Platforms) > 0 {
+		for _, e := range m.Platforms {
+			l = e.Size()
+			n += 1 + l + sovControl(uint64(l))
+		}
+	}
 	return n
 }
 
@@ -4663,6 +4689,37 @@
 			}
 			m.Labels[mapkey] = mapvalue
 			iNdEx = postIndex
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Platforms", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowControl
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthControl
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Platforms = append(m.Platforms, pb.Platform{})
+			if err := m.Platforms[len(m.Platforms)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipControl(dAtA[iNdEx:])
@@ -4792,80 +4849,81 @@
 func init() { proto.RegisterFile("control.proto", fileDescriptorControl) }
 
 var fileDescriptorControl = []byte{
-	// 1192 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x56, 0xcd, 0x6e, 0x23, 0x45,
-	0x10, 0x66, 0x6c, 0xc7, 0x3f, 0x65, 0x27, 0x0a, 0x0d, 0xac, 0x46, 0x03, 0x24, 0x66, 0x00, 0xc9,
-	0x8a, 0x76, 0xc7, 0xd9, 0xc0, 0x22, 0xc8, 0x61, 0xb5, 0xeb, 0x78, 0x11, 0x89, 0x12, 0xb1, 0x74,
-	0x36, 0xac, 0xc4, 0x6d, 0x6c, 0x77, 0xbc, 0xa3, 0xd8, 0xd3, 0xa6, 0xbb, 0x27, 0xda, 0xf0, 0x14,
-	0x1c, 0xb8, 0xf2, 0x14, 0x1c, 0x38, 0x73, 0x40, 0xda, 0x23, 0x67, 0x0e, 0x59, 0x94, 0x3b, 0x3c,
-	0x03, 0xea, 0x9f, 0xb1, 0xdb, 0x1e, 0xe7, 0xc7, 0xd9, 0x53, 0xba, 0x3a, 0x5f, 0x7d, 0x53, 0x5d,
-	0x5f, 0xb9, 0xaa, 0x60, 0xb9, 0x4b, 0x63, 0xc1, 0xe8, 0x20, 0x18, 0x31, 0x2a, 0x28, 0x5a, 0x1d,
-	0xd2, 0xce, 0x59, 0xd0, 0x49, 0xa2, 0x41, 0xef, 0x24, 0x12, 0xc1, 0xe9, 0x7d, 0xef, 0x5e, 0x3f,
-	0x12, 0x2f, 0x92, 0x4e, 0xd0, 0xa5, 0xc3, 0x66, 0x9f, 0xf6, 0x69, 0x53, 0x01, 0x3b, 0xc9, 0xb1,
-	0xb2, 0x94, 0xa1, 0x4e, 0x9a, 0xc0, 0x5b, 0xef, 0x53, 0xda, 0x1f, 0x90, 0x09, 0x4a, 0x44, 0x43,
-	0xc2, 0x45, 0x38, 0x1c, 0x19, 0xc0, 0x5d, 0x8b, 0x4f, 0x7e, 0xac, 0x99, 0x7e, 0xac, 0xc9, 0xe9,
-	0xe0, 0x94, 0xb0, 0xe6, 0xa8, 0xd3, 0xa4, 0x23, 0xae, 0xd1, 0xfe, 0x0a, 0xd4, 0x9e, 0xb2, 0x24,
-	0x26, 0x98, 0xfc, 0x98, 0x10, 0x2e, 0xfc, 0x0d, 0x58, 0x6d, 0x47, 0xfc, 0xe4, 0x88, 0x87, 0xfd,
-	0xf4, 0x0e, 0xdd, 0x81, 0xe2, 0x71, 0x34, 0x10, 0x84, 0xb9, 0x4e, 0xdd, 0x69, 0x54, 0xb0, 0xb1,
-	0xfc, 0x3d, 0x78, 0xdb, 0xc2, 0xf2, 0x11, 0x8d, 0x39, 0x41, 0x0f, 0xa0, 0xc8, 0x48, 0x97, 0xb2,
-	0x9e, 0xeb, 0xd4, 0xf3, 0x8d, 0xea, 0xd6, 0x87, 0xc1, 0xec, 0x8b, 0x03, 0xe3, 0x20, 0x41, 0xd8,
-	0x80, 0xfd, 0x3f, 0x72, 0x50, 0xb5, 0xee, 0xd1, 0x0a, 0xe4, 0x76, 0xdb, 0xe6, 0x7b, 0xb9, 0xdd,
-	0x36, 0x72, 0xa1, 0x74, 0x90, 0x88, 0xb0, 0x33, 0x20, 0x6e, 0xae, 0xee, 0x34, 0xca, 0x38, 0x35,
-	0xd1, 0xbb, 0xb0, 0xb4, 0x1b, 0x1f, 0x71, 0xe2, 0xe6, 0xd5, 0xbd, 0x36, 0x10, 0x82, 0xc2, 0x61,
-	0xf4, 0x13, 0x71, 0x0b, 0x75, 0xa7, 0x91, 0xc7, 0xea, 0x2c, 0xdf, 0xf1, 0x34, 0x64, 0x24, 0x16,
-	0xee, 0x92, 0x7e, 0x87, 0xb6, 0x50, 0x0b, 0x2a, 0x3b, 0x8c, 0x84, 0x82, 0xf4, 0x1e, 0x0b, 0xb7,
-	0x58, 0x77, 0x1a, 0xd5, 0x2d, 0x2f, 0xd0, 0x69, 0x0e, 0xd2, 0x34, 0x07, 0xcf, 0xd2, 0x34, 0xb7,
-	0xca, 0xaf, 0xce, 0xd7, 0xdf, 0xfa, 0xf9, 0xf5, 0xba, 0x83, 0x27, 0x6e, 0xe8, 0x11, 0xc0, 0x7e,
-	0xc8, 0xc5, 0x11, 0x57, 0x24, 0xa5, 0x6b, 0x49, 0x0a, 0x8a, 0xc0, 0xf2, 0x41, 0x6b, 0x00, 0x2a,
-	0x01, 0x3b, 0x34, 0x89, 0x85, 0x5b, 0x56, 0x71, 0x5b, 0x37, 0xa8, 0x0e, 0xd5, 0x36, 0xe1, 0x5d,
-	0x16, 0x8d, 0x44, 0x44, 0x63, 0xb7, 0xa2, 0x9e, 0x60, 0x5f, 0xf9, 0xbf, 0x14, 0xa0, 0x76, 0x28,
-	0x35, 0x4e, 0x85, 0x5b, 0x85, 0x3c, 0x26, 0xc7, 0x26, 0x8b, 0xf2, 0x88, 0x02, 0x80, 0x36, 0x39,
-	0x8e, 0xe2, 0x48, 0x71, 0xe4, 0x54, 0x98, 0x2b, 0xc1, 0xa8, 0x13, 0x4c, 0x6e, 0xb1, 0x85, 0x40,
-	0x1e, 0x94, 0x9f, 0xbc, 0x1c, 0x51, 0x26, 0xc5, 0xcf, 0x2b, 0x9a, 0xb1, 0x8d, 0x9e, 0xc3, 0x72,
-	0x7a, 0x7e, 0x2c, 0x04, 0xe3, 0x6e, 0x41, 0x09, 0x7e, 0x3f, 0x2b, 0xb8, 0x1d, 0x54, 0x30, 0xe5,
-	0xf3, 0x24, 0x16, 0xec, 0x0c, 0x4f, 0xf3, 0x48, 0xad, 0x0f, 0x09, 0xe7, 0x32, 0x42, 0x2d, 0x54,
-	0x6a, 0xca, 0x70, 0xbe, 0x66, 0x34, 0x16, 0x24, 0xee, 0x29, 0xa1, 0x2a, 0x78, 0x6c, 0xcb, 0x70,
-	0xd2, 0xb3, 0x0e, 0xa7, 0x74, 0xa3, 0x70, 0xa6, 0x7c, 0x4c, 0x38, 0x53, 0x77, 0x68, 0x1b, 0x96,
-	0x76, 0xc2, 0xee, 0x0b, 0xa2, 0x34, 0xa9, 0x6e, 0xad, 0x65, 0x09, 0xd5, 0xbf, 0xbf, 0x55, 0x22,
-	0xf0, 0x56, 0x41, 0x96, 0x07, 0xd6, 0x2e, 0xde, 0x23, 0x40, 0xd9, 0xf7, 0x4a, 0x5d, 0x4e, 0xc8,
-	0x59, 0xaa, 0xcb, 0x09, 0x39, 0x93, 0x45, 0x7c, 0x1a, 0x0e, 0x12, 0x5d, 0xdc, 0x15, 0xac, 0x8d,
-	0xed, 0xdc, 0x97, 0x8e, 0x64, 0xc8, 0x86, 0xb8, 0x08, 0x83, 0xff, 0xda, 0x81, 0x9a, 0x1d, 0x21,
-	0xfa, 0x00, 0x2a, 0x3a, 0xa8, 0x49, 0x71, 0x4c, 0x2e, 0x64, 0x1d, 0xee, 0x0e, 0x8d, 0xc1, 0xdd,
-	0x5c, 0x3d, 0xdf, 0xa8, 0x60, 0xeb, 0x06, 0x7d, 0x07, 0x55, 0x0d, 0xd6, 0x59, 0xce, 0xab, 0x2c,
-	0x37, 0xaf, 0x4e, 0x4a, 0x60, 0x79, 0xe8, 0x1c, 0xdb, 0x1c, 0xde, 0x43, 0x58, 0x9d, 0x05, 0x2c,
-	0xf4, 0xc2, 0xdf, 0x1d, 0x58, 0x36, 0xa2, 0x9a, 0x2e, 0x14, 0xa6, 0x8c, 0x84, 0xa5, 0x77, 0xa6,
-	0x1f, 0x3d, 0xb8, 0xb4, 0x1e, 0x34, 0x2c, 0x98, 0xf5, 0xd3, 0xf1, 0x66, 0xe8, 0xbc, 0x1d, 0x78,
-	0x6f, 0x2e, 0x74, 0xa1, 0xc8, 0x3f, 0x82, 0xe5, 0x43, 0x11, 0x8a, 0x84, 0x5f, 0xfa, 0x93, 0xf5,
-	0x7f, 0x73, 0x60, 0x25, 0xc5, 0x98, 0xd7, 0x7d, 0x0e, 0xe5, 0x53, 0xc2, 0x04, 0x79, 0x49, 0xb8,
-	0x79, 0x95, 0x9b, 0x7d, 0xd5, 0xf7, 0x0a, 0x81, 0xc7, 0x48, 0xb4, 0x0d, 0x65, 0xae, 0x78, 0x88,
-	0x96, 0x75, 0x6e, 0x29, 0x6b, 0x2f, 0xf3, 0xbd, 0x31, 0x1e, 0x35, 0xa1, 0x30, 0xa0, 0xfd, 0x54,
-	0xed, 0xf7, 0x2f, 0xf3, 0xdb, 0xa7, 0x7d, 0xac, 0x80, 0xfe, 0x79, 0x0e, 0x8a, 0xfa, 0x0e, 0xed,
-	0x41, 0xb1, 0x17, 0xf5, 0x09, 0x17, 0xfa, 0x55, 0xad, 0x2d, 0xf9, 0x03, 0xf9, 0xfb, 0x7c, 0x7d,
-	0xc3, 0x1a, 0x54, 0x74, 0x44, 0x62, 0x39, 0x28, 0xc3, 0x28, 0x26, 0x8c, 0x37, 0xfb, 0xf4, 0x9e,
-	0x76, 0x09, 0xda, 0xea, 0x0f, 0x36, 0x0c, 0x92, 0x2b, 0x8a, 0x47, 0x89, 0x30, 0x85, 0x79, 0x3b,
-	0x2e, 0xcd, 0x20, 0x47, 0x44, 0x1c, 0x0e, 0x89, 0xe9, 0x6b, 0xea, 0x2c, 0x47, 0x44, 0x57, 0xd6,
-	0x6d, 0x4f, 0x0d, 0x8e, 0x32, 0x36, 0x16, 0xda, 0x86, 0x12, 0x17, 0x21, 0x13, 0xa4, 0xa7, 0x5a,
-	0xd2, 0x4d, 0x7a, 0x7b, 0xea, 0x80, 0x1e, 0x42, 0xa5, 0x4b, 0x87, 0xa3, 0x01, 0x91, 0xde, 0xc5,
-	0x1b, 0x7a, 0x4f, 0x5c, 0x64, 0xf5, 0x10, 0xc6, 0x28, 0x53, 0x53, 0xa5, 0x82, 0xb5, 0xe1, 0xff,
-	0x97, 0x83, 0x9a, 0x2d, 0x56, 0x66, 0x62, 0xee, 0x41, 0x51, 0x4b, 0xaf, 0xab, 0xee, 0x76, 0xa9,
-	0xd2, 0x0c, 0x73, 0x53, 0xe5, 0x42, 0xa9, 0x9b, 0x30, 0x35, 0x4e, 0xf5, 0x90, 0x4d, 0x4d, 0x19,
-	0xb0, 0xa0, 0x22, 0x1c, 0xa8, 0x54, 0xe5, 0xb1, 0x36, 0xe4, 0x94, 0x1d, 0xaf, 0x2a, 0x8b, 0x4d,
-	0xd9, 0xb1, 0x9b, 0x2d, 0x43, 0xe9, 0x8d, 0x64, 0x28, 0x2f, 0x2c, 0x83, 0xff, 0xa7, 0x03, 0x95,
-	0x71, 0x95, 0x5b, 0xd9, 0x75, 0xde, 0x38, 0xbb, 0x53, 0x99, 0xc9, 0xdd, 0x2e, 0x33, 0x77, 0xa0,
-	0xc8, 0x05, 0x23, 0xe1, 0x50, 0x69, 0x94, 0xc7, 0xc6, 0x92, 0xfd, 0x64, 0xc8, 0xfb, 0x4a, 0xa1,
-	0x1a, 0x96, 0x47, 0xdf, 0x87, 0x5a, 0xeb, 0x4c, 0x10, 0x7e, 0x40, 0xb8, 0x5c, 0x2e, 0xa4, 0xb6,
-	0xbd, 0x50, 0x84, 0xea, 0x1d, 0x35, 0xac, 0xce, 0xfe, 0x5d, 0x40, 0xfb, 0x11, 0x17, 0xcf, 0x29,
-	0x3b, 0x21, 0x8c, 0xcf, 0xdb, 0x03, 0xf3, 0xd6, 0x1e, 0x78, 0x00, 0xef, 0x4c, 0xa1, 0x4d, 0x97,
-	0xfa, 0x62, 0x66, 0x13, 0x9c, 0xd3, 0x6d, 0xb4, 0xcb, 0xcc, 0x2a, 0xf8, 0xab, 0x03, 0x35, 0xfb,
-	0x1f, 0x99, 0xca, 0x6e, 0x41, 0x71, 0x3f, 0xec, 0x90, 0x41, 0xda, 0xc6, 0x36, 0xae, 0x26, 0x0e,
-	0x34, 0x58, 0xf7, 0x71, 0xe3, 0xe9, 0x7d, 0x05, 0x55, 0xeb, 0x7a, 0x91, 0x9e, 0xbd, 0xf5, 0x6f,
-	0x1e, 0x4a, 0x3b, 0x7a, 0xa9, 0x47, 0xcf, 0xa0, 0x32, 0x5e, 0x81, 0x91, 0x9f, 0x8d, 0x63, 0x76,
-	0x97, 0xf6, 0x3e, 0xbe, 0x12, 0x63, 0x32, 0xf7, 0x0d, 0x2c, 0xa9, 0xa5, 0x1c, 0xcd, 0x49, 0x99,
-	0xbd, 0xad, 0x7b, 0x57, 0x2f, 0xd7, 0x9b, 0x8e, 0x64, 0x52, 0xd3, 0x6d, 0x1e, 0x93, 0xbd, 0x06,
-	0x79, 0xeb, 0xd7, 0x8c, 0x45, 0x74, 0x00, 0x45, 0xd3, 0x68, 0xe6, 0x41, 0xed, 0x19, 0xe6, 0xd5,
-	0x2f, 0x07, 0x68, 0xb2, 0x4d, 0x07, 0x1d, 0x8c, 0x77, 0xbc, 0x79, 0xa1, 0xd9, 0x05, 0xea, 0x5d,
-	0xf3, 0xff, 0x86, 0xb3, 0xe9, 0xa0, 0x1f, 0xa0, 0x6a, 0x95, 0x20, 0xfa, 0x24, 0xeb, 0x92, 0xad,
-	0x67, 0xef, 0xd3, 0x6b, 0x50, 0x3a, 0xd8, 0x56, 0xed, 0xd5, 0xc5, 0x9a, 0xf3, 0xd7, 0xc5, 0x9a,
-	0xf3, 0xcf, 0xc5, 0x9a, 0xd3, 0x29, 0xaa, 0x5f, 0xe4, 0x67, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff,
-	0x4d, 0x94, 0x5a, 0xb6, 0xd8, 0x0d, 0x00, 0x00,
+	// 1214 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x57, 0x4f, 0x6f, 0x1b, 0x55,
+	0x10, 0x67, 0x6d, 0xc7, 0xf6, 0x8e, 0x9d, 0x28, 0x3c, 0xa0, 0x5a, 0x2d, 0x90, 0x98, 0x05, 0x24,
+	0xab, 0x6a, 0xd7, 0x69, 0xa0, 0x08, 0x72, 0xa8, 0x5a, 0xc7, 0x45, 0x24, 0x4a, 0x44, 0xd8, 0x34,
+	0x54, 0xe2, 0xb6, 0xb6, 0x5f, 0xdc, 0x55, 0xd6, 0xfb, 0x96, 0xf7, 0x9e, 0xa3, 0x86, 0x4f, 0xc1,
+	0x81, 0x6f, 0xc2, 0x81, 0x33, 0x07, 0xa4, 0xde, 0xe0, 0xcc, 0x21, 0x45, 0xb9, 0xc3, 0x67, 0x40,
+	0xef, 0xcf, 0xda, 0xcf, 0x5e, 0xe7, 0x8f, 0xd3, 0x93, 0xdf, 0xcc, 0xfe, 0xe6, 0xb7, 0xf3, 0x66,
+	0x66, 0x67, 0xc6, 0xb0, 0xdc, 0x23, 0x09, 0xa7, 0x24, 0xf6, 0x53, 0x4a, 0x38, 0x41, 0xab, 0x43,
+	0xd2, 0x3d, 0xf3, 0xbb, 0xa3, 0x28, 0xee, 0x9f, 0x44, 0xdc, 0x3f, 0x7d, 0xe0, 0xde, 0x1f, 0x44,
+	0xfc, 0xc5, 0xa8, 0xeb, 0xf7, 0xc8, 0xb0, 0x35, 0x20, 0x03, 0xd2, 0x92, 0xc0, 0xee, 0xe8, 0x58,
+	0x4a, 0x52, 0x90, 0x27, 0x45, 0xe0, 0xae, 0x0f, 0x08, 0x19, 0xc4, 0x78, 0x82, 0xe2, 0xd1, 0x10,
+	0x33, 0x1e, 0x0e, 0x53, 0x0d, 0xb8, 0x67, 0xf0, 0x89, 0x97, 0xb5, 0xb2, 0x97, 0xb5, 0x18, 0x89,
+	0x4f, 0x31, 0x6d, 0xa5, 0xdd, 0x16, 0x49, 0x99, 0x42, 0x7b, 0x2b, 0x50, 0x3f, 0xa0, 0xa3, 0x04,
+	0x07, 0xf8, 0xc7, 0x11, 0x66, 0xdc, 0xbb, 0x0b, 0xab, 0x9d, 0x88, 0x9d, 0x1c, 0xb1, 0x70, 0x90,
+	0xe9, 0xd0, 0x1d, 0x28, 0x1f, 0x47, 0x31, 0xc7, 0xd4, 0xb1, 0x1a, 0x56, 0xd3, 0x0e, 0xb4, 0xe4,
+	0xed, 0xc2, 0xdb, 0x06, 0x96, 0xa5, 0x24, 0x61, 0x18, 0x3d, 0x84, 0x32, 0xc5, 0x3d, 0x42, 0xfb,
+	0x8e, 0xd5, 0x28, 0x36, 0x6b, 0x9b, 0x1f, 0xfa, 0xb3, 0x37, 0xf6, 0xb5, 0x81, 0x00, 0x05, 0x1a,
+	0xec, 0xfd, 0x5e, 0x80, 0x9a, 0xa1, 0x47, 0x2b, 0x50, 0xd8, 0xe9, 0xe8, 0xf7, 0x15, 0x76, 0x3a,
+	0xc8, 0x81, 0xca, 0xfe, 0x88, 0x87, 0xdd, 0x18, 0x3b, 0x85, 0x86, 0xd5, 0xac, 0x06, 0x99, 0x88,
+	0xde, 0x85, 0xa5, 0x9d, 0xe4, 0x88, 0x61, 0xa7, 0x28, 0xf5, 0x4a, 0x40, 0x08, 0x4a, 0x87, 0xd1,
+	0x4f, 0xd8, 0x29, 0x35, 0xac, 0x66, 0x31, 0x90, 0x67, 0x71, 0x8f, 0x83, 0x90, 0xe2, 0x84, 0x3b,
+	0x4b, 0xea, 0x1e, 0x4a, 0x42, 0x6d, 0xb0, 0xb7, 0x29, 0x0e, 0x39, 0xee, 0x3f, 0xe1, 0x4e, 0xb9,
+	0x61, 0x35, 0x6b, 0x9b, 0xae, 0xaf, 0xc2, 0xec, 0x67, 0x61, 0xf6, 0x9f, 0x65, 0x61, 0x6e, 0x57,
+	0x5f, 0x9d, 0xaf, 0xbf, 0xf5, 0xf3, 0xeb, 0x75, 0x2b, 0x98, 0x98, 0xa1, 0xc7, 0x00, 0x7b, 0x21,
+	0xe3, 0x47, 0x4c, 0x92, 0x54, 0xae, 0x25, 0x29, 0x49, 0x02, 0xc3, 0x06, 0xad, 0x01, 0xc8, 0x00,
+	0x6c, 0x93, 0x51, 0xc2, 0x9d, 0xaa, 0xf4, 0xdb, 0xd0, 0xa0, 0x06, 0xd4, 0x3a, 0x98, 0xf5, 0x68,
+	0x94, 0xf2, 0x88, 0x24, 0x8e, 0x2d, 0xaf, 0x60, 0xaa, 0xbc, 0x5f, 0x4a, 0x50, 0x3f, 0x14, 0x39,
+	0xce, 0x12, 0xb7, 0x0a, 0xc5, 0x00, 0x1f, 0xeb, 0x28, 0x8a, 0x23, 0xf2, 0x01, 0x3a, 0xf8, 0x38,
+	0x4a, 0x22, 0xc9, 0x51, 0x90, 0x6e, 0xae, 0xf8, 0x69, 0xd7, 0x9f, 0x68, 0x03, 0x03, 0x81, 0x5c,
+	0xa8, 0x3e, 0x7d, 0x99, 0x12, 0x2a, 0x92, 0x5f, 0x94, 0x34, 0x63, 0x19, 0x3d, 0x87, 0xe5, 0xec,
+	0xfc, 0x84, 0x73, 0xca, 0x9c, 0x92, 0x4c, 0xf8, 0x83, 0x7c, 0xc2, 0x4d, 0xa7, 0xfc, 0x29, 0x9b,
+	0xa7, 0x09, 0xa7, 0x67, 0xc1, 0x34, 0x8f, 0xc8, 0xf5, 0x21, 0x66, 0x4c, 0x78, 0xa8, 0x12, 0x95,
+	0x89, 0xc2, 0x9d, 0xaf, 0x29, 0x49, 0x38, 0x4e, 0xfa, 0x32, 0x51, 0x76, 0x30, 0x96, 0x85, 0x3b,
+	0xd9, 0x59, 0xb9, 0x53, 0xb9, 0x91, 0x3b, 0x53, 0x36, 0xda, 0x9d, 0x29, 0x1d, 0xda, 0x82, 0xa5,
+	0xed, 0xb0, 0xf7, 0x02, 0xcb, 0x9c, 0xd4, 0x36, 0xd7, 0xf2, 0x84, 0xf2, 0xf1, 0xb7, 0x32, 0x09,
+	0xac, 0x5d, 0x12, 0xe5, 0x11, 0x28, 0x13, 0xf7, 0x31, 0xa0, 0xfc, 0x7d, 0x45, 0x5e, 0x4e, 0xf0,
+	0x59, 0x96, 0x97, 0x13, 0x7c, 0x26, 0x8a, 0xf8, 0x34, 0x8c, 0x47, 0xaa, 0xb8, 0xed, 0x40, 0x09,
+	0x5b, 0x85, 0x2f, 0x2d, 0xc1, 0x90, 0x77, 0x71, 0x11, 0x06, 0xef, 0xb5, 0x05, 0x75, 0xd3, 0x43,
+	0xf4, 0x01, 0xd8, 0xca, 0xa9, 0x49, 0x71, 0x4c, 0x14, 0xa2, 0x0e, 0x77, 0x86, 0x5a, 0x60, 0x4e,
+	0xa1, 0x51, 0x6c, 0xda, 0x81, 0xa1, 0x41, 0xdf, 0x41, 0x4d, 0x81, 0x55, 0x94, 0x8b, 0x32, 0xca,
+	0xad, 0xab, 0x83, 0xe2, 0x1b, 0x16, 0x2a, 0xc6, 0x26, 0x87, 0xfb, 0x08, 0x56, 0x67, 0x01, 0x0b,
+	0xdd, 0xf0, 0x37, 0x0b, 0x96, 0x75, 0x52, 0x75, 0x17, 0x0a, 0x33, 0x46, 0x4c, 0x33, 0x9d, 0xee,
+	0x47, 0x0f, 0x2f, 0xad, 0x07, 0x05, 0xf3, 0x67, 0xed, 0x94, 0xbf, 0x39, 0x3a, 0x77, 0x1b, 0xde,
+	0x9b, 0x0b, 0x5d, 0xc8, 0xf3, 0x8f, 0x60, 0xf9, 0x90, 0x87, 0x7c, 0xc4, 0x2e, 0xfd, 0x64, 0xbd,
+	0x5f, 0x2d, 0x58, 0xc9, 0x30, 0xfa, 0x76, 0x9f, 0x43, 0xf5, 0x14, 0x53, 0x8e, 0x5f, 0x62, 0xa6,
+	0x6f, 0xe5, 0xe4, 0x6f, 0xf5, 0xbd, 0x44, 0x04, 0x63, 0x24, 0xda, 0x82, 0x2a, 0x93, 0x3c, 0x58,
+	0xa5, 0x75, 0x6e, 0x29, 0x2b, 0x2b, 0xfd, 0xbe, 0x31, 0x1e, 0xb5, 0xa0, 0x14, 0x93, 0x41, 0x96,
+	0xed, 0xf7, 0x2f, 0xb3, 0xdb, 0x23, 0x83, 0x40, 0x02, 0xbd, 0xf3, 0x02, 0x94, 0x95, 0x0e, 0xed,
+	0x42, 0xb9, 0x1f, 0x0d, 0x30, 0xe3, 0xea, 0x56, 0xed, 0x4d, 0xf1, 0x81, 0xfc, 0x7d, 0xbe, 0x7e,
+	0xd7, 0x18, 0x54, 0x24, 0xc5, 0x89, 0x18, 0x94, 0x61, 0x94, 0x60, 0xca, 0x5a, 0x03, 0x72, 0x5f,
+	0x99, 0xf8, 0x1d, 0xf9, 0x13, 0x68, 0x06, 0xc1, 0x15, 0x25, 0xe9, 0x88, 0xeb, 0xc2, 0xbc, 0x1d,
+	0x97, 0x62, 0x10, 0x23, 0x22, 0x09, 0x87, 0x58, 0xf7, 0x35, 0x79, 0x16, 0x23, 0xa2, 0x27, 0xea,
+	0xb6, 0x2f, 0x07, 0x47, 0x35, 0xd0, 0x12, 0xda, 0x82, 0x0a, 0xe3, 0x21, 0xe5, 0xb8, 0x2f, 0x5b,
+	0xd2, 0x4d, 0x7a, 0x7b, 0x66, 0x80, 0x1e, 0x81, 0xdd, 0x23, 0xc3, 0x34, 0xc6, 0xc2, 0xba, 0x7c,
+	0x43, 0xeb, 0x89, 0x89, 0xa8, 0x1e, 0x4c, 0x29, 0xa1, 0x72, 0xaa, 0xd8, 0x81, 0x12, 0xbc, 0xff,
+	0x0a, 0x50, 0x37, 0x93, 0x95, 0x9b, 0x98, 0xbb, 0x50, 0x56, 0xa9, 0x57, 0x55, 0x77, 0xbb, 0x50,
+	0x29, 0x86, 0xb9, 0xa1, 0x72, 0xa0, 0xd2, 0x1b, 0x51, 0x39, 0x4e, 0xd5, 0x90, 0xcd, 0x44, 0xe1,
+	0x30, 0x27, 0x3c, 0x8c, 0x65, 0xa8, 0x8a, 0x81, 0x12, 0xc4, 0x94, 0x1d, 0xaf, 0x2a, 0x8b, 0x4d,
+	0xd9, 0xb1, 0x99, 0x99, 0x86, 0xca, 0x1b, 0xa5, 0xa1, 0xba, 0x70, 0x1a, 0xbc, 0x3f, 0x2c, 0xb0,
+	0xc7, 0x55, 0x6e, 0x44, 0xd7, 0x7a, 0xe3, 0xe8, 0x4e, 0x45, 0xa6, 0x70, 0xbb, 0xc8, 0xdc, 0x81,
+	0x32, 0xe3, 0x14, 0x87, 0x43, 0x99, 0xa3, 0x62, 0xa0, 0x25, 0xd1, 0x4f, 0x86, 0x6c, 0x20, 0x33,
+	0x54, 0x0f, 0xc4, 0xd1, 0xf3, 0xa0, 0xde, 0x3e, 0xe3, 0x98, 0xed, 0x63, 0x26, 0x96, 0x0b, 0x91,
+	0xdb, 0x7e, 0xc8, 0x43, 0x79, 0x8f, 0x7a, 0x20, 0xcf, 0xde, 0x3d, 0x40, 0x7b, 0x11, 0xe3, 0xcf,
+	0x09, 0x3d, 0xc1, 0x94, 0xcd, 0xdb, 0x03, 0x8b, 0xc6, 0x1e, 0xb8, 0x0f, 0xef, 0x4c, 0xa1, 0x75,
+	0x97, 0xfa, 0x62, 0x66, 0x13, 0x9c, 0xd3, 0x6d, 0x94, 0xc9, 0xcc, 0x2a, 0xf8, 0xa7, 0x05, 0x75,
+	0xf3, 0x41, 0xae, 0xb2, 0xdb, 0x50, 0xde, 0x0b, 0xbb, 0x38, 0xce, 0xda, 0xd8, 0xdd, 0xab, 0x89,
+	0x7d, 0x05, 0x56, 0x7d, 0x5c, 0x5b, 0xa2, 0x0d, 0xb0, 0xd3, 0x38, 0xe4, 0xc7, 0x84, 0x0e, 0xb3,
+	0xae, 0x56, 0x17, 0x7b, 0xd0, 0x81, 0x56, 0xea, 0x31, 0x3e, 0x01, 0xb9, 0x5f, 0x41, 0xcd, 0x20,
+	0x5a, 0xa4, 0xcb, 0x6f, 0xfe, 0x5b, 0x84, 0xca, 0xb6, 0xfa, 0x1b, 0x80, 0x9e, 0x81, 0x3d, 0x5e,
+	0x9a, 0x91, 0x97, 0xf7, 0x7c, 0x76, 0xfb, 0x76, 0x3f, 0xbe, 0x12, 0xa3, 0x63, 0xfd, 0x0d, 0x2c,
+	0xc9, 0x35, 0x1e, 0xcd, 0x09, 0xb2, 0xb9, 0xdf, 0xbb, 0x57, 0xaf, 0xe3, 0x1b, 0x96, 0x60, 0x92,
+	0xf3, 0x70, 0x1e, 0x93, 0xb9, 0x38, 0xb9, 0xeb, 0xd7, 0x0c, 0x52, 0xb4, 0x0f, 0x65, 0xdd, 0x9a,
+	0xe6, 0x41, 0xcd, 0xa9, 0xe7, 0x36, 0x2e, 0x07, 0x28, 0xb2, 0x0d, 0x0b, 0xed, 0x8f, 0xb7, 0xc2,
+	0x79, 0xae, 0x99, 0x25, 0xed, 0x5e, 0xf3, 0xbc, 0x69, 0x6d, 0x58, 0xe8, 0x07, 0xa8, 0x19, 0x45,
+	0x8b, 0x3e, 0xc9, 0x9b, 0xe4, 0xbf, 0x00, 0xf7, 0xd3, 0x6b, 0x50, 0xca, 0xd9, 0x76, 0xfd, 0xd5,
+	0xc5, 0x9a, 0xf5, 0xd7, 0xc5, 0x9a, 0xf5, 0xcf, 0xc5, 0x9a, 0xd5, 0x2d, 0xcb, 0x6f, 0xf8, 0xb3,
+	0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x86, 0xd4, 0x0f, 0xa1, 0x0a, 0x0e, 0x00, 0x00,
 }
diff --git a/vendor/github.com/moby/buildkit/api/services/control/control.proto b/vendor/github.com/moby/buildkit/api/services/control/control.proto
index 7944ce8..9768920 100644
--- a/vendor/github.com/moby/buildkit/api/services/control/control.proto
+++ b/vendor/github.com/moby/buildkit/api/services/control/control.proto
@@ -118,4 +118,5 @@
 message WorkerRecord {
 	string ID = 1;
 	map<string, string> Labels = 2;
+	repeated pb.Platform platforms = 3 [(gogoproto.nullable) = false];
 }
diff --git a/vendor/github.com/moby/buildkit/cache/manager.go b/vendor/github.com/moby/buildkit/cache/manager.go
index f0ea2e7..a10cb9e 100644
--- a/vendor/github.com/moby/buildkit/cache/manager.go
+++ b/vendor/github.com/moby/buildkit/cache/manager.go
@@ -17,7 +17,7 @@
 )
 
 var (
-	errLocked   = errors.New("locked")
+	ErrLocked   = errors.New("locked")
 	errNotFound = errors.New("not found")
 	errInvalid  = errors.New("invalid")
 )
@@ -122,7 +122,7 @@
 
 	if rec.mutable {
 		if len(rec.refs) != 0 {
-			return nil, errors.Wrapf(errLocked, "%s is locked", id)
+			return nil, errors.Wrapf(ErrLocked, "%s is locked", id)
 		}
 		if rec.equalImmutable != nil {
 			return rec.equalImmutable.ref(), nil
@@ -279,12 +279,12 @@
 	}
 
 	if len(rec.refs) != 0 {
-		return nil, errors.Wrapf(errLocked, "%s is locked", id)
+		return nil, errors.Wrapf(ErrLocked, "%s is locked", id)
 	}
 
 	if rec.equalImmutable != nil {
 		if len(rec.equalImmutable.refs) != 0 {
-			return nil, errors.Wrapf(errLocked, "%s is locked", id)
+			return nil, errors.Wrapf(ErrLocked, "%s is locked", id)
 		}
 		delete(cm.records, rec.equalImmutable.ID())
 		if err := rec.equalImmutable.remove(ctx, false); err != nil {
@@ -513,7 +513,7 @@
 }
 
 func IsLocked(err error) bool {
-	return errors.Cause(err) == errLocked
+	return errors.Cause(err) == ErrLocked
 }
 
 func IsNotFound(err error) bool {
diff --git a/vendor/github.com/moby/buildkit/client/client.go b/vendor/github.com/moby/buildkit/client/client.go
index c71c00c..403ed52 100644
--- a/vendor/github.com/moby/buildkit/client/client.go
+++ b/vendor/github.com/moby/buildkit/client/client.go
@@ -5,7 +5,6 @@
 	"crypto/tls"
 	"crypto/x509"
 	"io/ioutil"
-	"time"
 
 	"github.com/grpc-ecosystem/grpc-opentracing/go/otgrpc"
 	controlapi "github.com/moby/buildkit/api/services/control"
@@ -23,7 +22,7 @@
 type ClientOpt interface{}
 
 // New returns a new buildkit client. Address can be empty for the system-default address.
-func New(address string, opts ...ClientOpt) (*Client, error) {
+func New(ctx context.Context, address string, opts ...ClientOpt) (*Client, error) {
 	gopts := []grpc.DialOption{
 		grpc.WithDialer(dialer),
 		grpc.FailOnNonTempDialError(true),
@@ -54,9 +53,6 @@
 		address = appdefaults.Address
 	}
 
-	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
-	defer cancel()
-
 	conn, err := grpc.DialContext(ctx, address, gopts...)
 	if err != nil {
 		return nil, errors.Wrapf(err, "failed to dial %q . make sure buildkitd is running", address)
diff --git a/vendor/github.com/moby/buildkit/client/llb/exec.go b/vendor/github.com/moby/buildkit/client/llb/exec.go
index 98be265..9dec170 100644
--- a/vendor/github.com/moby/buildkit/client/llb/exec.go
+++ b/vendor/github.com/moby/buildkit/client/llb/exec.go
@@ -17,8 +17,8 @@
 	ProxyEnv *ProxyEnv
 }
 
-func NewExecOp(root Output, meta Meta, readOnly bool, md OpMetadata) *ExecOp {
-	e := &ExecOp{meta: meta, cachedOpMetadata: md}
+func NewExecOp(root Output, meta Meta, readOnly bool, c Constraints) *ExecOp {
+	e := &ExecOp{meta: meta, constraints: c}
 	rootMount := &mount{
 		target:   pb.RootMount,
 		source:   root,
@@ -28,32 +28,35 @@
 	if readOnly {
 		e.root = root
 	} else {
-		e.root = &output{vertex: e, getIndex: e.getMountIndexFn(rootMount)}
+		o := &output{vertex: e, getIndex: e.getMountIndexFn(rootMount)}
+		if p := c.Platform; p != nil {
+			o.platform = p
+		}
+		e.root = o
 	}
 	rootMount.output = e.root
-
 	return e
 }
 
 type mount struct {
-	target   string
-	readonly bool
-	source   Output
-	output   Output
-	selector string
-	cacheID  string
-	tmpfs    bool
+	target       string
+	readonly     bool
+	source       Output
+	output       Output
+	selector     string
+	cacheID      string
+	tmpfs        bool
+	cacheSharing CacheMountSharingMode
 	// hasOutput bool
 }
 
 type ExecOp struct {
-	root             Output
-	mounts           []*mount
-	meta             Meta
-	cachedPBDigest   digest.Digest
-	cachedPB         []byte
-	cachedOpMetadata OpMetadata
-	isValidated      bool
+	MarshalCache
+	root        Output
+	mounts      []*mount
+	meta        Meta
+	constraints Constraints
+	isValidated bool
 }
 
 func (e *ExecOp) AddMount(target string, source Output, opt ...MountOption) Output {
@@ -70,9 +73,13 @@
 	} else if m.tmpfs {
 		m.output = &output{vertex: e, err: errors.Errorf("tmpfs mount for %s can't be used as a parent", target)}
 	} else {
-		m.output = &output{vertex: e, getIndex: e.getMountIndexFn(m)}
+		o := &output{vertex: e, getIndex: e.getMountIndexFn(m)}
+		if p := e.constraints.Platform; p != nil {
+			o.platform = p
+		}
+		m.output = o
 	}
-	e.cachedPB = nil
+	e.Store(nil, nil, nil)
 	e.isValidated = false
 	return m.output
 }
@@ -107,9 +114,9 @@
 	return nil
 }
 
-func (e *ExecOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
-	if e.cachedPB != nil {
-		return e.cachedPBDigest, e.cachedPB, &e.cachedOpMetadata, nil
+func (e *ExecOp) Marshal(c *Constraints) (digest.Digest, []byte, *pb.OpMetadata, error) {
+	if e.Cached(c) {
+		return e.Load()
 	}
 	if err := e.Validate(); err != nil {
 		return "", nil, nil, err
@@ -137,10 +144,9 @@
 		}
 	}
 
-	pop := &pb.Op{
-		Op: &pb.Op_Exec{
-			Exec: peo,
-		},
+	pop, md := MarshalConstraints(c, &e.constraints)
+	pop.Op = &pb.Op_Exec{
+		Exec: peo,
 	}
 
 	outIndex := 0
@@ -150,7 +156,7 @@
 			if m.tmpfs {
 				return "", nil, nil, errors.Errorf("tmpfs mounts must use scratch")
 			}
-			inp, err := m.source.ToInput()
+			inp, err := m.source.ToInput(c)
 			if err != nil {
 				return "", nil, nil, err
 			}
@@ -190,6 +196,14 @@
 			pm.CacheOpt = &pb.CacheOpt{
 				ID: m.cacheID,
 			}
+			switch m.cacheSharing {
+			case CacheMountShared:
+				pm.CacheOpt.Sharing = pb.CacheSharingOpt_SHARED
+			case CacheMountPrivate:
+				pm.CacheOpt.Sharing = pb.CacheSharingOpt_PRIVATE
+			case CacheMountLocked:
+				pm.CacheOpt.Sharing = pb.CacheSharingOpt_LOCKED
+			}
 		}
 		if m.tmpfs {
 			pm.MountType = pb.MountType_TMPFS
@@ -201,9 +215,8 @@
 	if err != nil {
 		return "", nil, nil, err
 	}
-	e.cachedPBDigest = digest.FromBytes(dt)
-	e.cachedPB = dt
-	return e.cachedPBDigest, dt, &e.cachedOpMetadata, nil
+	e.Store(dt, md, c)
+	return e.Load()
 }
 
 func (e *ExecOp) Output() Output {
@@ -273,9 +286,10 @@
 	}
 }
 
-func AsPersistentCacheDir(id string) MountOption {
+func AsPersistentCacheDir(id string, sharing CacheMountSharingMode) MountOption {
 	return func(m *mount) {
 		m.cacheID = id
+		m.cacheSharing = sharing
 	}
 }
 
@@ -366,7 +380,7 @@
 }
 
 type ExecInfo struct {
-	opMetaWrapper
+	constraintsWrapper
 	State          State
 	Mounts         []MountInfo
 	ReadonlyRootFS bool
@@ -385,3 +399,11 @@
 	FtpProxy   string
 	NoProxy    string
 }
+
+type CacheMountSharingMode int
+
+const (
+	CacheMountShared CacheMountSharingMode = iota
+	CacheMountPrivate
+	CacheMountLocked
+)
diff --git a/vendor/github.com/moby/buildkit/client/llb/imagemetaresolver/resolver.go b/vendor/github.com/moby/buildkit/client/llb/imagemetaresolver/resolver.go
index d7d0d74..09d4aec 100644
--- a/vendor/github.com/moby/buildkit/client/llb/imagemetaresolver/resolver.go
+++ b/vendor/github.com/moby/buildkit/client/llb/imagemetaresolver/resolver.go
@@ -12,6 +12,7 @@
 	"github.com/moby/buildkit/util/contentutil"
 	"github.com/moby/buildkit/util/imageutil"
 	digest "github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 var defaultImageMetaResolver llb.ImageMetaResolver
@@ -22,12 +23,12 @@
 })
 
 type imageMetaResolverOpts struct {
-	platform string
+	platform *specs.Platform
 }
 
 type ImageMetaResolverOpt func(o *imageMetaResolverOpts)
 
-func WithPlatform(p string) ImageMetaResolverOpt {
+func WithDefaultPlatform(p *specs.Platform) ImageMetaResolverOpt {
 	return func(o *imageMetaResolverOpts) {
 		o.platform = p
 	}
@@ -59,7 +60,7 @@
 type imageMetaResolver struct {
 	resolver remotes.Resolver
 	buffer   contentutil.Buffer
-	platform string
+	platform *specs.Platform
 	locker   *locker.Locker
 	cache    map[string]resolveResult
 }
@@ -69,7 +70,7 @@
 	dgst   digest.Digest
 }
 
-func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error) {
+func (imr *imageMetaResolver) ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error) {
 	imr.locker.Lock(ref)
 	defer imr.locker.Unlock(ref)
 
@@ -77,7 +78,11 @@
 		return res.dgst, res.config, nil
 	}
 
-	dgst, config, err := imageutil.Config(ctx, ref, imr.resolver, imr.buffer, imr.platform)
+	if platform == nil {
+		platform = imr.platform
+	}
+
+	dgst, config, err := imageutil.Config(ctx, ref, imr.resolver, imr.buffer, platform)
 	if err != nil {
 		return "", nil, err
 	}
diff --git a/vendor/github.com/moby/buildkit/client/llb/marshal.go b/vendor/github.com/moby/buildkit/client/llb/marshal.go
index 4d8ad55..65a352f 100644
--- a/vendor/github.com/moby/buildkit/client/llb/marshal.go
+++ b/vendor/github.com/moby/buildkit/client/llb/marshal.go
@@ -4,6 +4,7 @@
 	"io"
 	"io/ioutil"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/moby/buildkit/solver/pb"
 	digest "github.com/opencontainers/go-digest"
 )
@@ -12,11 +13,11 @@
 // Corresponds to the Definition structure defined in solver/pb.Definition.
 type Definition struct {
 	Def      [][]byte
-	Metadata map[digest.Digest]OpMetadata
+	Metadata map[digest.Digest]pb.OpMetadata
 }
 
 func (def *Definition) ToPB() *pb.Definition {
-	md := make(map[digest.Digest]OpMetadata)
+	md := make(map[digest.Digest]pb.OpMetadata)
 	for k, v := range def.Metadata {
 		md[k] = v
 	}
@@ -28,14 +29,12 @@
 
 func (def *Definition) FromPB(x *pb.Definition) {
 	def.Def = x.Def
-	def.Metadata = make(map[digest.Digest]OpMetadata)
+	def.Metadata = make(map[digest.Digest]pb.OpMetadata)
 	for k, v := range x.Metadata {
 		def.Metadata[k] = v
 	}
 }
 
-type OpMetadata = pb.OpMetadata
-
 func WriteTo(def *Definition, w io.Writer) error {
 	b, err := def.ToPB().Marshal()
 	if err != nil {
@@ -58,3 +57,56 @@
 	def.FromPB(&pbDef)
 	return &def, nil
 }
+
+func MarshalConstraints(base, override *Constraints) (*pb.Op, *pb.OpMetadata) {
+	c := *base
+	c.WorkerConstraints = append([]string{}, c.WorkerConstraints...)
+
+	if p := override.Platform; p != nil {
+		c.Platform = p
+	}
+
+	for _, wc := range override.WorkerConstraints {
+		c.WorkerConstraints = append(c.WorkerConstraints, wc)
+	}
+
+	c.Metadata = mergeMetadata(c.Metadata, override.Metadata)
+
+	if c.Platform == nil {
+		defaultPlatform := platforms.Normalize(platforms.DefaultSpec())
+		c.Platform = &defaultPlatform
+	}
+
+	return &pb.Op{
+		Platform: &pb.Platform{
+			OS:           c.Platform.OS,
+			Architecture: c.Platform.Architecture,
+			Variant:      c.Platform.Variant,
+			OSVersion:    c.Platform.OSVersion,
+			OSFeatures:   c.Platform.OSFeatures,
+		},
+		Constraints: &pb.WorkerConstraints{
+			Filter: c.WorkerConstraints,
+		},
+	}, &c.Metadata
+}
+
+type MarshalCache struct {
+	digest      digest.Digest
+	dt          []byte
+	md          *pb.OpMetadata
+	constraints *Constraints
+}
+
+func (mc *MarshalCache) Cached(c *Constraints) bool {
+	return mc.dt != nil && mc.constraints == c
+}
+func (mc *MarshalCache) Load() (digest.Digest, []byte, *pb.OpMetadata, error) {
+	return mc.digest, mc.dt, mc.md, nil
+}
+func (mc *MarshalCache) Store(dt []byte, md *pb.OpMetadata, c *Constraints) {
+	mc.digest = digest.FromBytes(dt)
+	mc.dt = dt
+	mc.md = md
+	mc.constraints = c
+}
diff --git a/vendor/github.com/moby/buildkit/client/llb/meta.go b/vendor/github.com/moby/buildkit/client/llb/meta.go
index 54449ff..22aea09 100644
--- a/vendor/github.com/moby/buildkit/client/llb/meta.go
+++ b/vendor/github.com/moby/buildkit/client/llb/meta.go
@@ -4,16 +4,19 @@
 	"fmt"
 	"path"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/google/shlex"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 type contextKeyT string
 
 var (
-	keyArgs = contextKeyT("llb.exec.args")
-	keyDir  = contextKeyT("llb.exec.dir")
-	keyEnv  = contextKeyT("llb.exec.env")
-	keyUser = contextKeyT("llb.exec.user")
+	keyArgs     = contextKeyT("llb.exec.args")
+	keyDir      = contextKeyT("llb.exec.dir")
+	keyEnv      = contextKeyT("llb.exec.env")
+	keyUser     = contextKeyT("llb.exec.user")
+	keyPlatform = contextKeyT("llb.platform")
 )
 
 func addEnv(key, value string) StateOption {
@@ -106,6 +109,21 @@
 	}
 }
 
+func platform(p specs.Platform) StateOption {
+	return func(s State) State {
+		return s.WithValue(keyPlatform, platforms.Normalize(p))
+	}
+}
+
+func getPlatform(s State) *specs.Platform {
+	v := s.Value(keyPlatform)
+	if v != nil {
+		p := v.(specs.Platform)
+		return &p
+	}
+	return nil
+}
+
 type EnvList []KeyValue
 
 type KeyValue struct {
diff --git a/vendor/github.com/moby/buildkit/client/llb/resolver.go b/vendor/github.com/moby/buildkit/client/llb/resolver.go
index bac738c..b539b11 100644
--- a/vendor/github.com/moby/buildkit/client/llb/resolver.go
+++ b/vendor/github.com/moby/buildkit/client/llb/resolver.go
@@ -4,6 +4,7 @@
 	"context"
 
 	digest "github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 func WithMetaResolver(mr ImageMetaResolver) ImageOption {
@@ -13,5 +14,5 @@
 }
 
 type ImageMetaResolver interface {
-	ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error)
+	ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error)
 }
diff --git a/vendor/github.com/moby/buildkit/client/llb/source.go b/vendor/github.com/moby/buildkit/client/llb/source.go
index 5b1bf06..f0f2968 100644
--- a/vendor/github.com/moby/buildkit/client/llb/source.go
+++ b/vendor/github.com/moby/buildkit/client/llb/source.go
@@ -15,22 +15,21 @@
 )
 
 type SourceOp struct {
-	id               string
-	attrs            map[string]string
-	output           Output
-	cachedPBDigest   digest.Digest
-	cachedPB         []byte
-	cachedOpMetadata OpMetadata
-	err              error
+	MarshalCache
+	id          string
+	attrs       map[string]string
+	output      Output
+	constraints Constraints
+	err         error
 }
 
-func NewSource(id string, attrs map[string]string, md OpMetadata) *SourceOp {
+func NewSource(id string, attrs map[string]string, c Constraints) *SourceOp {
 	s := &SourceOp{
-		id:               id,
-		attrs:            attrs,
-		cachedOpMetadata: md,
+		id:          id,
+		attrs:       attrs,
+		constraints: c,
 	}
-	s.output = &output{vertex: s}
+	s.output = &output{vertex: s, platform: c.Platform}
 	return s
 }
 
@@ -44,26 +43,26 @@
 	return nil
 }
 
-func (s *SourceOp) Marshal() (digest.Digest, []byte, *OpMetadata, error) {
-	if s.cachedPB != nil {
-		return s.cachedPBDigest, s.cachedPB, &s.cachedOpMetadata, nil
+func (s *SourceOp) Marshal(constraints *Constraints) (digest.Digest, []byte, *pb.OpMetadata, error) {
+	if s.Cached(constraints) {
+		return s.Load()
 	}
 	if err := s.Validate(); err != nil {
 		return "", nil, nil, err
 	}
 
-	proto := &pb.Op{
-		Op: &pb.Op_Source{
-			Source: &pb.SourceOp{Identifier: s.id, Attrs: s.attrs},
-		},
+	proto, md := MarshalConstraints(constraints, &s.constraints)
+
+	proto.Op = &pb.Op_Source{
+		Source: &pb.SourceOp{Identifier: s.id, Attrs: s.attrs},
 	}
 	dt, err := proto.Marshal()
 	if err != nil {
 		return "", nil, nil, err
 	}
-	s.cachedPB = dt
-	s.cachedPBDigest = digest.FromBytes(dt)
-	return s.cachedPBDigest, dt, &s.cachedOpMetadata, nil
+
+	s.Store(dt, md, constraints)
+	return s.Load()
 }
 
 func (s *SourceOp) Output() Output {
@@ -74,10 +73,6 @@
 	return nil
 }
 
-func Source(id string) State {
-	return NewState(NewSource(id, nil, OpMetadata{}).Output())
-}
-
 func Image(ref string, opts ...ImageOption) State {
 	r, err := reference.ParseNormalizedNamed(ref)
 	if err == nil {
@@ -87,12 +82,12 @@
 	for _, opt := range opts {
 		opt.SetImageOption(&info)
 	}
-	src := NewSource("docker-image://"+ref, nil, info.Metadata()) // controversial
+	src := NewSource("docker-image://"+ref, nil, info.Constraints) // controversial
 	if err != nil {
 		src.err = err
 	}
 	if info.metaResolver != nil {
-		_, dt, err := info.metaResolver.ResolveImageConfig(context.TODO(), ref)
+		_, dt, err := info.metaResolver.ResolveImageConfig(context.TODO(), ref, info.Constraints.Platform)
 		if err != nil {
 			src.err = err
 		} else {
@@ -136,7 +131,7 @@
 }
 
 type ImageInfo struct {
-	opMetaWrapper
+	constraintsWrapper
 	metaResolver ImageMetaResolver
 }
 
@@ -169,7 +164,7 @@
 	if url != "" {
 		attrs[pb.AttrFullRemoteURL] = url
 	}
-	source := NewSource("git://"+id, attrs, gi.Metadata())
+	source := NewSource("git://"+id, attrs, gi.Constraints)
 	return NewState(source.Output())
 }
 
@@ -183,7 +178,7 @@
 }
 
 type GitInfo struct {
-	opMetaWrapper
+	constraintsWrapper
 	KeepGitDir bool
 }
 
@@ -220,7 +215,7 @@
 		attrs[pb.AttrSharedKeyHint] = gi.SharedKeyHint
 	}
 
-	source := NewSource("local://"+name, attrs, gi.Metadata())
+	source := NewSource("local://"+name, attrs, gi.Constraints)
 	return NewState(source.Output())
 }
 
@@ -280,7 +275,7 @@
 }
 
 type LocalInfo struct {
-	opMetaWrapper
+	constraintsWrapper
 	SessionID       string
 	IncludePatterns string
 	ExcludePatterns string
@@ -310,12 +305,12 @@
 		attrs[pb.AttrHTTPGID] = strconv.Itoa(hi.GID)
 	}
 
-	source := NewSource(url, attrs, hi.Metadata())
+	source := NewSource(url, attrs, hi.Constraints)
 	return NewState(source.Output())
 }
 
 type HTTPInfo struct {
-	opMetaWrapper
+	constraintsWrapper
 	Checksum digest.Digest
 	Filename string
 	Perm     int
diff --git a/vendor/github.com/moby/buildkit/client/llb/state.go b/vendor/github.com/moby/buildkit/client/llb/state.go
index a53b212..f9e2138 100644
--- a/vendor/github.com/moby/buildkit/client/llb/state.go
+++ b/vendor/github.com/moby/buildkit/client/llb/state.go
@@ -3,21 +3,23 @@
 import (
 	"context"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/util/system"
 	digest "github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 type StateOption func(State) State
 
 type Output interface {
-	ToInput() (*pb.Input, error)
+	ToInput(*Constraints) (*pb.Input, error)
 	Vertex() Vertex
 }
 
 type Vertex interface {
 	Validate() error
-	Marshal() (digest.Digest, []byte, *OpMetadata, error)
+	Marshal(*Constraints) (digest.Digest, []byte, *pb.OpMetadata, error)
 	Output() Output
 	Inputs() []Output
 }
@@ -29,12 +31,25 @@
 	}
 	s = dir("/")(s)
 	s = addEnv("PATH", system.DefaultPathEnv)(s)
+	s = s.ensurePlatform()
 	return s
 }
 
 type State struct {
-	out Output
-	ctx context.Context
+	out  Output
+	ctx  context.Context
+	opts []ConstraintsOpt
+}
+
+func (s State) ensurePlatform() State {
+	if o, ok := s.out.(interface {
+		Platform() *specs.Platform
+	}); ok {
+		if p := o.Platform(); p != nil {
+			s = platform(*p)(s)
+		}
+	}
+	return s
 }
 
 func (s State) WithValue(k, v interface{}) State {
@@ -48,18 +63,32 @@
 	return s.ctx.Value(k)
 }
 
-func (s State) Marshal(md ...MetadataOpt) (*Definition, error) {
+func (s State) SetMarhalDefaults(co ...ConstraintsOpt) State {
+	s.opts = co
+	return s
+}
+
+func (s State) Marshal(co ...ConstraintsOpt) (*Definition, error) {
 	def := &Definition{
-		Metadata: make(map[digest.Digest]OpMetadata, 0),
+		Metadata: make(map[digest.Digest]pb.OpMetadata, 0),
 	}
 	if s.Output() == nil {
 		return def, nil
 	}
-	def, err := marshal(s.Output().Vertex(), def, map[digest.Digest]struct{}{}, map[Vertex]struct{}{}, md)
+
+	defaultPlatform := platforms.Normalize(platforms.DefaultSpec())
+	c := &Constraints{
+		Platform: &defaultPlatform,
+	}
+	for _, o := range append(s.opts, co...) {
+		o.SetConstraintsOption(c)
+	}
+
+	def, err := marshal(s.Output().Vertex(), def, map[digest.Digest]struct{}{}, map[Vertex]struct{}{}, c)
 	if err != nil {
 		return def, err
 	}
-	inp, err := s.Output().ToInput()
+	inp, err := s.Output().ToInput(c)
 	if err != nil {
 		return def, err
 	}
@@ -72,29 +101,25 @@
 	return def, nil
 }
 
-func marshal(v Vertex, def *Definition, cache map[digest.Digest]struct{}, vertexCache map[Vertex]struct{}, md []MetadataOpt) (*Definition, error) {
+func marshal(v Vertex, def *Definition, cache map[digest.Digest]struct{}, vertexCache map[Vertex]struct{}, c *Constraints) (*Definition, error) {
 	if _, ok := vertexCache[v]; ok {
 		return def, nil
 	}
 	for _, inp := range v.Inputs() {
 		var err error
-		def, err = marshal(inp.Vertex(), def, cache, vertexCache, md)
+		def, err = marshal(inp.Vertex(), def, cache, vertexCache, c)
 		if err != nil {
 			return def, err
 		}
 	}
 
-	dgst, dt, opMeta, err := v.Marshal()
+	dgst, dt, opMeta, err := v.Marshal(c)
 	if err != nil {
 		return def, err
 	}
 	vertexCache[v] = struct{}{}
 	if opMeta != nil {
-		m := mergeMetadata(def.Metadata[dgst], *opMeta)
-		for _, f := range md {
-			f.SetMetadataOption(&m)
-		}
-		def.Metadata[dgst] = m
+		def.Metadata[dgst] = mergeMetadata(def.Metadata[dgst], *opMeta)
 	}
 	if _, ok := cache[dgst]; ok {
 		return def, nil
@@ -113,14 +138,19 @@
 }
 
 func (s State) WithOutput(o Output) State {
-	return State{
+	s = State{
 		out: o,
 		ctx: s.ctx,
 	}
+	s = s.ensurePlatform()
+	return s
 }
 
 func (s State) Run(ro ...RunOption) ExecState {
 	ei := &ExecInfo{State: s}
+	if p := s.GetPlatform(); p != nil {
+		ei.Constraints.Platform = p
+	}
 	for _, o := range ro {
 		o.SetRunOption(ei)
 	}
@@ -132,7 +162,7 @@
 		ProxyEnv: ei.ProxyEnv,
 	}
 
-	exec := NewExecOp(s.Output(), meta, ei.ReadonlyRootFS, ei.Metadata())
+	exec := NewExecOp(s.Output(), meta, ei.ReadonlyRootFS, ei.Constraints)
 	for _, m := range ei.Mounts {
 		exec.AddMount(m.Target, m.Source, m.Opts...)
 	}
@@ -178,6 +208,14 @@
 	return user(v)(s)
 }
 
+func (s State) Platform(p specs.Platform) State {
+	return platform(p)(s)
+}
+
+func (s State) GetPlatform() *specs.Platform {
+	return getPlatform(s)
+}
+
 func (s State) With(so ...StateOption) State {
 	for _, o := range so {
 		s = o(s)
@@ -189,9 +227,10 @@
 	vertex   Vertex
 	getIndex func() (pb.OutputIndex, error)
 	err      error
+	platform *specs.Platform
 }
 
-func (o *output) ToInput() (*pb.Input, error) {
+func (o *output) ToInput(c *Constraints) (*pb.Input, error) {
 	if o.err != nil {
 		return nil, o.err
 	}
@@ -203,7 +242,7 @@
 			return nil, err
 		}
 	}
-	dgst, _, _, err := o.vertex.Marshal()
+	dgst, _, _, err := o.vertex.Marshal(c)
 	if err != nil {
 		return nil, err
 	}
@@ -214,8 +253,12 @@
 	return o.vertex
 }
 
-type MetadataOpt interface {
-	SetMetadataOption(*OpMetadata)
+func (o *output) Platform() *specs.Platform {
+	return o.platform
+}
+
+type ConstraintsOpt interface {
+	SetConstraintsOption(*Constraints)
 	RunOption
 	LocalOption
 	HTTPOption
@@ -223,33 +266,33 @@
 	GitOption
 }
 
-type metadataOptFunc func(m *OpMetadata)
+type constraintsOptFunc func(m *Constraints)
 
-func (fn metadataOptFunc) SetMetadataOption(m *OpMetadata) {
+func (fn constraintsOptFunc) SetConstraintsOption(m *Constraints) {
 	fn(m)
 }
 
-func (fn metadataOptFunc) SetRunOption(ei *ExecInfo) {
-	ei.ApplyMetadata(fn)
+func (fn constraintsOptFunc) SetRunOption(ei *ExecInfo) {
+	ei.applyConstraints(fn)
 }
 
-func (fn metadataOptFunc) SetLocalOption(li *LocalInfo) {
-	li.ApplyMetadata(fn)
+func (fn constraintsOptFunc) SetLocalOption(li *LocalInfo) {
+	li.applyConstraints(fn)
 }
 
-func (fn metadataOptFunc) SetHTTPOption(hi *HTTPInfo) {
-	hi.ApplyMetadata(fn)
+func (fn constraintsOptFunc) SetHTTPOption(hi *HTTPInfo) {
+	hi.applyConstraints(fn)
 }
 
-func (fn metadataOptFunc) SetImageOption(ii *ImageInfo) {
-	ii.ApplyMetadata(fn)
+func (fn constraintsOptFunc) SetImageOption(ii *ImageInfo) {
+	ii.applyConstraints(fn)
 }
 
-func (fn metadataOptFunc) SetGitOption(gi *GitInfo) {
-	gi.ApplyMetadata(fn)
+func (fn constraintsOptFunc) SetGitOption(gi *GitInfo) {
+	gi.applyConstraints(fn)
 }
 
-func mergeMetadata(m1, m2 OpMetadata) OpMetadata {
+func mergeMetadata(m1, m2 pb.OpMetadata) pb.OpMetadata {
 	if m2.IgnoreCache {
 		m1.IgnoreCache = true
 	}
@@ -268,49 +311,77 @@
 	return m1
 }
 
-var IgnoreCache = metadataOptFunc(func(md *OpMetadata) {
-	md.IgnoreCache = true
+var IgnoreCache = constraintsOptFunc(func(c *Constraints) {
+	c.Metadata.IgnoreCache = true
 })
 
-func WithDescription(m map[string]string) MetadataOpt {
-	return metadataOptFunc(func(md *OpMetadata) {
-		md.Description = m
+func WithDescription(m map[string]string) ConstraintsOpt {
+	return constraintsOptFunc(func(c *Constraints) {
+		c.Metadata.Description = m
 	})
 }
 
 // WithExportCache forces results for this vertex to be exported with the cache
-func WithExportCache() MetadataOpt {
-	return metadataOptFunc(func(md *OpMetadata) {
-		md.ExportCache = &pb.ExportCache{Value: true}
+func WithExportCache() ConstraintsOpt {
+	return constraintsOptFunc(func(c *Constraints) {
+		c.Metadata.ExportCache = &pb.ExportCache{Value: true}
 	})
 }
 
 // WithoutExportCache sets results for this vertex to be not exported with
 // the cache
-func WithoutExportCache() MetadataOpt {
-	return metadataOptFunc(func(md *OpMetadata) {
+func WithoutExportCache() ConstraintsOpt {
+	return constraintsOptFunc(func(c *Constraints) {
 		// ExportCache with value false means to disable exporting
-		md.ExportCache = &pb.ExportCache{Value: false}
+		c.Metadata.ExportCache = &pb.ExportCache{Value: false}
 	})
 }
 
 // WithoutDefaultExportCache resets the cache export for the vertex to use
 // the default defined by the build configuration.
-func WithoutDefaultExportCache() MetadataOpt {
-	return metadataOptFunc(func(md *OpMetadata) {
+func WithoutDefaultExportCache() ConstraintsOpt {
+	return constraintsOptFunc(func(c *Constraints) {
 		// nil means no vertex based config has been set
-		md.ExportCache = nil
+		c.Metadata.ExportCache = nil
 	})
 }
 
-type opMetaWrapper struct {
-	OpMetadata
+type constraintsWrapper struct {
+	Constraints
 }
 
-func (mw *opMetaWrapper) ApplyMetadata(f func(m *OpMetadata)) {
-	f(&mw.OpMetadata)
+func (cw *constraintsWrapper) applyConstraints(f func(c *Constraints)) {
+	f(&cw.Constraints)
 }
 
-func (mw *opMetaWrapper) Metadata() OpMetadata {
-	return mw.OpMetadata
+type Constraints struct {
+	Platform          *specs.Platform
+	WorkerConstraints []string
+	Metadata          pb.OpMetadata
+}
+
+func Platform(p specs.Platform) ConstraintsOpt {
+	return constraintsOptFunc(func(c *Constraints) {
+		c.Platform = &p
+	})
+}
+
+var (
+	LinuxAmd64   = Platform(specs.Platform{OS: "linux", Architecture: "amd64"})
+	LinuxArmhf   = Platform(specs.Platform{OS: "linux", Architecture: "arm", Variant: "v7"})
+	LinuxArm     = LinuxArmhf
+	LinuxArmel   = Platform(specs.Platform{OS: "linux", Architecture: "arm", Variant: "v6"})
+	LinuxArm64   = Platform(specs.Platform{OS: "linux", Architecture: "arm64"})
+	LinuxS390x   = Platform(specs.Platform{OS: "linux", Architecture: "s390x"})
+	LinuxPpc64le = Platform(specs.Platform{OS: "linux", Architecture: "ppc64le"})
+	Darwin       = Platform(specs.Platform{OS: "darwin", Architecture: "amd64"})
+	Windows      = Platform(specs.Platform{OS: "windows", Architecture: "amd64"})
+)
+
+func Require(filters ...string) ConstraintsOpt {
+	return constraintsOptFunc(func(c *Constraints) {
+		for _, f := range filters {
+			c.WorkerConstraints = append(c.WorkerConstraints, f)
+		}
+	})
 }
diff --git a/vendor/github.com/moby/buildkit/client/workers.go b/vendor/github.com/moby/buildkit/client/workers.go
index b4ccb82..2645a59 100644
--- a/vendor/github.com/moby/buildkit/client/workers.go
+++ b/vendor/github.com/moby/buildkit/client/workers.go
@@ -4,12 +4,15 @@
 	"context"
 
 	controlapi "github.com/moby/buildkit/api/services/control"
+	"github.com/moby/buildkit/solver/pb"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
 type WorkerInfo struct {
-	ID     string
-	Labels map[string]string
+	ID        string
+	Labels    map[string]string
+	Platforms []specs.Platform
 }
 
 func (c *Client) ListWorkers(ctx context.Context, opts ...ListWorkersOption) ([]*WorkerInfo, error) {
@@ -28,8 +31,9 @@
 
 	for _, w := range resp.Record {
 		wi = append(wi, &WorkerInfo{
-			ID:     w.ID,
-			Labels: w.Labels,
+			ID:        w.ID,
+			Labels:    w.Labels,
+			Platforms: toClientPlatforms(w.Platforms),
 		})
 	}
 
@@ -47,3 +51,17 @@
 		wi.Filter = f
 	}
 }
+
+func toClientPlatforms(p []pb.Platform) []specs.Platform {
+	out := make([]specs.Platform, 0, len(p))
+	for _, pp := range p {
+		out = append(out, specs.Platform{
+			OS:           pp.OS,
+			Architecture: pp.Architecture,
+			Variant:      pp.Variant,
+			OSVersion:    pp.OSVersion,
+			OSFeatures:   pp.OSFeatures,
+		})
+	}
+	return out
+}
diff --git a/vendor/github.com/moby/buildkit/control/control.go b/vendor/github.com/moby/buildkit/control/control.go
index ac90605..2460df8 100644
--- a/vendor/github.com/moby/buildkit/control/control.go
+++ b/vendor/github.com/moby/buildkit/control/control.go
@@ -13,7 +13,9 @@
 	"github.com/moby/buildkit/session/grpchijack"
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/solver/llbsolver"
+	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/worker"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/sync/errgroup"
@@ -35,7 +37,10 @@
 }
 
 func NewController(opt Opt) (*Controller, error) {
-	solver := llbsolver.New(opt.WorkerController, opt.Frontends, opt.CacheKeyStorage, opt.CacheImporter)
+	solver, err := llbsolver.New(opt.WorkerController, opt.Frontends, opt.CacheKeyStorage, opt.CacheImporter)
+	if err != nil {
+		return nil, errors.Wrap(err, "failed to create solver")
+	}
 
 	c := &Controller{
 		opt:    opt,
@@ -265,8 +270,9 @@
 	}
 	for _, w := range workers {
 		resp.Record = append(resp.Record, &controlapi.WorkerRecord{
-			ID:     w.ID(),
-			Labels: w.Labels(),
+			ID:        w.ID(),
+			Labels:    w.Labels(),
+			Platforms: toPBPlatforms(w.Platforms()),
 		})
 	}
 	return resp, nil
@@ -290,3 +296,17 @@
 	}
 	return solver.CacheExportModeMin
 }
+
+func toPBPlatforms(p []specs.Platform) []pb.Platform {
+	out := make([]pb.Platform, 0, len(p))
+	for _, pp := range p {
+		out = append(out, pb.Platform{
+			OS:           pp.OS,
+			Architecture: pp.Architecture,
+			Variant:      pp.Variant,
+			OSVersion:    pp.OSVersion,
+			OSFeatures:   pp.OSFeatures,
+		})
+	}
+	return out
+}
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/builder/build.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/builder/build.go
index 9aee2a7..c618f38 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/builder/build.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/builder/build.go
@@ -8,10 +8,12 @@
 	"regexp"
 	"strings"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/docker/builder/dockerignore"
 	"github.com/moby/buildkit/client/llb"
 	"github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb"
 	"github.com/moby/buildkit/frontend/gateway/client"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"golang.org/x/sync/errgroup"
 )
@@ -28,14 +30,26 @@
 	buildArgPrefix        = "build-arg:"
 	labelPrefix           = "label:"
 	keyNoCache            = "no-cache"
+	keyTargetPlatform     = "platform"
 )
 
 var httpPrefix = regexp.MustCompile("^https?://")
-var gitUrlPathWithFragmentSuffix = regexp.MustCompile(".git(?:#.+)?$")
+var gitUrlPathWithFragmentSuffix = regexp.MustCompile("\\.git(?:#.+)?$")
 
 func Build(ctx context.Context, c client.Client) error {
 	opts := c.Opts()
 
+	// TODO: read buildPlatforms from workers
+	buildPlatforms := []specs.Platform{platforms.DefaultSpec()}
+	targetPlatform := platforms.DefaultSpec()
+	if v := opts[keyTargetPlatform]; v != "" {
+		var err error
+		targetPlatform, err = platforms.Parse(v)
+		if err != nil {
+			return errors.Wrapf(err, "failed to parse target platform %s", v)
+		}
+	}
+
 	filename := opts[keyFilename]
 	if filename == "" {
 		filename = defaultDockerfileName
@@ -166,14 +180,16 @@
 	}
 
 	st, img, err := dockerfile2llb.Dockerfile2LLB(ctx, dtDockerfile, dockerfile2llb.ConvertOpt{
-		Target:       opts[keyTarget],
-		MetaResolver: c,
-		BuildArgs:    filter(opts, buildArgPrefix),
-		Labels:       filter(opts, labelPrefix),
-		SessionID:    c.SessionID(),
-		BuildContext: buildContext,
-		Excludes:     excludes,
-		IgnoreCache:  ignoreCache,
+		Target:         opts[keyTarget],
+		MetaResolver:   c,
+		BuildArgs:      filter(opts, buildArgPrefix),
+		Labels:         filter(opts, labelPrefix),
+		SessionID:      c.SessionID(),
+		BuildContext:   buildContext,
+		Excludes:       excludes,
+		IgnoreCache:    ignoreCache,
+		TargetPlatform: &targetPlatform,
+		BuildPlatforms: buildPlatforms,
 	})
 
 	if err != nil {
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go
index 756d7e1..00e92b3 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert.go
@@ -12,6 +12,7 @@
 	"strconv"
 	"strings"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/docker/distribution/reference"
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/go-connections/nat"
@@ -20,7 +21,7 @@
 	"github.com/moby/buildkit/frontend/dockerfile/instructions"
 	"github.com/moby/buildkit/frontend/dockerfile/parser"
 	"github.com/moby/buildkit/frontend/dockerfile/shell"
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"golang.org/x/sync/errgroup"
 )
@@ -30,7 +31,7 @@
 	localNameContext = "context"
 	historyComment   = "buildkit.dockerfile.v0"
 
-	CopyImage = "tonistiigi/copy:v0.1.3@sha256:87c46e7b413cdd2c2702902b481b390ce263ac9d942253d366f3b1a3c16f96d6"
+	CopyImage = "tonistiigi/copy:v0.1.3@sha256:e57a3b4d6240f55bac26b655d2cfb751f8b9412d6f7bb1f787e946391fb4b21b"
 )
 
 type ConvertOpt struct {
@@ -46,6 +47,8 @@
 	IgnoreCache []string
 	// CacheIDNamespace scopes the IDs for different cache mounts
 	CacheIDNamespace string
+	TargetPlatform   *specs.Platform
+	BuildPlatforms   []specs.Platform
 }
 
 func Dockerfile2LLB(ctx context.Context, dt []byte, opt ConvertOpt) (*llb.State, *Image, error) {
@@ -53,6 +56,18 @@
 		return nil, nil, errors.Errorf("the Dockerfile cannot be empty")
 	}
 
+	if opt.TargetPlatform != nil && opt.BuildPlatforms == nil {
+		opt.BuildPlatforms = []specs.Platform{*opt.TargetPlatform}
+	}
+	if len(opt.BuildPlatforms) == 0 {
+		opt.BuildPlatforms = []specs.Platform{platforms.DefaultSpec()}
+	}
+	implicitTargetPlatform := false
+	if opt.TargetPlatform == nil {
+		implicitTargetPlatform = true
+		opt.TargetPlatform = &opt.BuildPlatforms[0]
+	}
+
 	dockerfile, err := parser.Parse(bytes.NewReader(dt))
 	if err != nil {
 		return nil, nil, err
@@ -92,6 +107,20 @@
 			deps:     make(map[*dispatchState]struct{}),
 			ctxPaths: make(map[string]struct{}),
 		}
+
+		if v := st.Platform; v != "" {
+			v, err := shlex.ProcessWord(v, toEnvList(metaArgs, nil))
+			if err != nil {
+				return nil, nil, errors.Wrapf(err, "failed to process arguments for platform %s", v)
+			}
+
+			p, err := platforms.Parse(v)
+			if err != nil {
+				return nil, nil, errors.Wrapf(err, "failed to parse platform %s", v)
+			}
+			ds.platform = &p
+		}
+
 		if d, ok := dispatchStatesByName[st.BaseName]; ok {
 			ds.base = d
 		}
@@ -150,7 +179,7 @@
 		if d.base == nil {
 			if d.stage.BaseName == emptyImageName {
 				d.state = llb.Scratch()
-				d.image = emptyImage()
+				d.image = emptyImage(*opt.TargetPlatform)
 				continue
 			}
 			func(i int, d *dispatchState) {
@@ -159,16 +188,25 @@
 					if err != nil {
 						return err
 					}
+					platform := d.platform
+					if platform == nil {
+						platform = opt.TargetPlatform
+					}
 					d.stage.BaseName = reference.TagNameOnly(ref).String()
 					var isScratch bool
 					if metaResolver != nil && reachable {
-						dgst, dt, err := metaResolver.ResolveImageConfig(ctx, d.stage.BaseName)
+						dgst, dt, err := metaResolver.ResolveImageConfig(ctx, d.stage.BaseName, platform)
 						if err == nil { // handle the error while builder is actually running
 							var img Image
 							if err := json.Unmarshal(dt, &img); err != nil {
 								return err
 							}
 							img.Created = nil
+							// if there is no explicit target platform, try to match based on image config
+							if d.platform == nil && implicitTargetPlatform {
+								p := autoDetectPlatform(img, *platform, opt.BuildPlatforms)
+								platform = &p
+							}
 							d.image = img
 							if dgst != "" {
 								ref, err = reference.WithDigest(ref, dgst)
@@ -186,7 +224,7 @@
 					if isScratch {
 						d.state = llb.Scratch()
 					} else {
-						d.state = llb.Image(d.stage.BaseName, dfCmd(d.stage.SourceCode))
+						d.state = llb.Image(d.stage.BaseName, dfCmd(d.stage.SourceCode), llb.Platform(*platform))
 					}
 					return nil
 				})
@@ -242,6 +280,8 @@
 			buildContext:         llb.NewState(buildContext),
 			proxyEnv:             proxyEnv,
 			cacheIDNamespace:     opt.CacheIDNamespace,
+			buildPlatforms:       opt.BuildPlatforms,
+			targetPlatform:       *opt.TargetPlatform,
 		}
 
 		if err = dispatchOnBuild(d, d.image.Config.OnBuild, opt); err != nil {
@@ -280,7 +320,14 @@
 	}
 	buildContext.Output = bc.Output()
 
-	return &target.state, &target.image, nil
+	st := target.state.SetMarhalDefaults(llb.Platform(*opt.TargetPlatform))
+
+	if !implicitTargetPlatform {
+		target.image.OS = opt.TargetPlatform.OS
+		target.image.Architecture = opt.TargetPlatform.Architecture
+	}
+
+	return &st, &target.image, nil
 }
 
 func toCommand(ic instructions.Command, dispatchStatesByName map[string]*dispatchState, allDispatchStates []*dispatchState) (command, error) {
@@ -325,6 +372,8 @@
 	buildContext         llb.State
 	proxyEnv             *llb.ProxyEnv
 	cacheIDNamespace     string
+	targetPlatform       specs.Platform
+	buildPlatforms       []specs.Platform
 }
 
 func dispatch(d *dispatchState, cmd command, opt dispatchOpt) error {
@@ -348,7 +397,7 @@
 	case *instructions.WorkdirCommand:
 		err = dispatchWorkdir(d, c, true)
 	case *instructions.AddCommand:
-		err = dispatchCopy(d, c.SourcesAndDest, opt.buildContext, true, c, "")
+		err = dispatchCopy(d, c.SourcesAndDest, opt.buildContext, true, c, "", opt)
 		if err == nil {
 			for _, src := range c.Sources() {
 				d.ctxPaths[path.Join("/", filepath.ToSlash(src))] = struct{}{}
@@ -381,7 +430,7 @@
 		if len(cmd.sources) != 0 {
 			l = cmd.sources[0].state
 		}
-		err = dispatchCopy(d, c.SourcesAndDest, l, false, c, c.Chown)
+		err = dispatchCopy(d, c.SourcesAndDest, l, false, c, c.Chown, opt)
 		if err == nil && len(cmd.sources) == 0 {
 			for _, src := range c.Sources() {
 				d.ctxPaths[path.Join("/", filepath.ToSlash(src))] = struct{}{}
@@ -395,6 +444,7 @@
 type dispatchState struct {
 	state        llb.State
 	image        Image
+	platform     *specs.Platform
 	stage        instructions.Stage
 	base         *dispatchState
 	deps         map[*dispatchState]struct{}
@@ -467,7 +517,11 @@
 		opt = append(opt, llb.WithProxy(*proxy))
 	}
 
-	opt = append(opt, dispatchRunMounts(d, c, sources, dopt)...)
+	runMounts, err := dispatchRunMounts(d, c, sources, dopt)
+	if err != nil {
+		return err
+	}
+	opt = append(opt, runMounts...)
 
 	d.state = d.state.Run(opt...).Root()
 	return commitToHistory(&d.image, "RUN "+runCommandString(args, d.buildArgs), true, &d.state)
@@ -486,9 +540,9 @@
 	return nil
 }
 
-func dispatchCopy(d *dispatchState, c instructions.SourcesAndDest, sourceState llb.State, isAddCommand bool, cmdToPrint interface{}, chown string) error {
+func dispatchCopy(d *dispatchState, c instructions.SourcesAndDest, sourceState llb.State, isAddCommand bool, cmdToPrint interface{}, chown string, opt dispatchOpt) error {
 	// TODO: this should use CopyOp instead. Current implementation is inefficient
-	img := llb.Image(CopyImage)
+	img := llb.Image(CopyImage, llb.Platform(opt.buildPlatforms[0]))
 
 	dest := path.Join(".", pathRelativeToWorkingDir(d.state, c.Dest()))
 	if c.Dest() == "." || c.Dest()[len(c.Dest())-1] == filepath.Separator {
@@ -554,12 +608,12 @@
 		args = append(args[:1], append([]string{"--unpack"}, args[1:]...)...)
 	}
 
-	opt := []llb.RunOption{llb.Args(args), llb.Dir("/dest"), llb.ReadonlyRootFS(), dfCmd(cmdToPrint)}
+	runOpt := []llb.RunOption{llb.Args(args), llb.Dir("/dest"), llb.ReadonlyRootFS(), dfCmd(cmdToPrint)}
 	if d.ignoreCache {
-		opt = append(opt, llb.IgnoreCache)
+		runOpt = append(runOpt, llb.IgnoreCache)
 	}
-	run := img.Run(append(opt, mounts...)...)
-	d.state = run.AddMount("/dest", d.state)
+	run := img.Run(append(runOpt, mounts...)...)
+	d.state = run.AddMount("/dest", d.state).Platform(opt.targetPlatform)
 
 	return commitToHistory(&d.image, commitMessage.String(), true, &d.state)
 }
@@ -767,7 +821,7 @@
 	return v
 }
 
-func dfCmd(cmd interface{}) llb.MetadataOpt {
+func dfCmd(cmd interface{}) llb.ConstraintsOpt {
 	// TODO: add fmt.Stringer to instructions.Command to remove interface{}
 	var cmdStr string
 	if cmd, ok := cmd.(fmt.Stringer); ok {
@@ -798,7 +852,7 @@
 		msg += " # buildkit"
 	}
 
-	img.History = append(img.History, ocispec.History{
+	img.History = append(img.History, specs.History{
 		CreatedBy:  msg,
 		Comment:    historyComment,
 		EmptyLayer: !withLayer,
@@ -930,3 +984,17 @@
 	}
 	return append(shell, strings.Join(args, " "))
 }
+
+func autoDetectPlatform(img Image, target specs.Platform, supported []specs.Platform) specs.Platform {
+	os := img.OS
+	arch := img.Architecture
+	if target.OS == os && target.Architecture == arch {
+		return target
+	}
+	for _, p := range supported {
+		if p.OS == os && p.Architecture == arch {
+			return p
+		}
+	}
+	return target
+}
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_norunmount.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_norunmount.go
index b358ee6..a4544e7 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_norunmount.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_norunmount.go
@@ -11,6 +11,6 @@
 	return false
 }
 
-func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*dispatchState, opt dispatchOpt) []llb.RunOption {
-	return nil
+func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*dispatchState, opt dispatchOpt) ([]llb.RunOption, error) {
+	return nil, nil
 }
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go
index f1b2029..61408e1 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/convert_runmount.go
@@ -9,6 +9,7 @@
 
 	"github.com/moby/buildkit/client/llb"
 	"github.com/moby/buildkit/frontend/dockerfile/instructions"
+	"github.com/pkg/errors"
 )
 
 func detectRunMount(cmd *command, dispatchStatesByName map[string]*dispatchState, allDispatchStates []*dispatchState) bool {
@@ -40,7 +41,7 @@
 	return false
 }
 
-func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*dispatchState, opt dispatchOpt) []llb.RunOption {
+func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*dispatchState, opt dispatchOpt) ([]llb.RunOption, error) {
 	var out []llb.RunOption
 	mounts := instructions.GetMounts(c)
 
@@ -61,14 +62,25 @@
 			mountOpts = append(mountOpts, llb.Readonly)
 		}
 		if mount.Type == instructions.MountTypeCache {
-			mountOpts = append(mountOpts, llb.AsPersistentCacheDir(opt.cacheIDNamespace+"/"+mount.CacheID))
+			sharing := llb.CacheMountShared
+			if mount.CacheSharing == instructions.MountSharingPrivate {
+				sharing = llb.CacheMountPrivate
+			}
+			if mount.CacheSharing == instructions.MountSharingLocked {
+				sharing = llb.CacheMountLocked
+			}
+			mountOpts = append(mountOpts, llb.AsPersistentCacheDir(opt.cacheIDNamespace+"/"+mount.CacheID, sharing))
+		}
+		target := path.Join("/", mount.Target)
+		if target == "/" {
+			return nil, errors.Errorf("invalid mount target %q", mount.Target)
 		}
 		if src := path.Join("/", mount.Source); src != "/" {
 			mountOpts = append(mountOpts, llb.SourcePath(src))
 		}
-		out = append(out, llb.AddMount(path.Join("/", mount.Target), st, mountOpts...))
+		out = append(out, llb.AddMount(target, st, mountOpts...))
 
 		d.ctxPaths[path.Join("/", filepath.ToSlash(mount.Source))] = struct{}{}
 	}
-	return out
+	return out, nil
 }
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/image.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/image.go
index 59c464a..6085d1e 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/image.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/dockerfile2llb/image.go
@@ -1,12 +1,11 @@
 package dockerfile2llb
 
 import (
-	"runtime"
 	"time"
 
 	"github.com/docker/docker/api/types/strslice"
 	"github.com/moby/buildkit/util/system"
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 // HealthConfig holds configuration settings for the HEALTHCHECK feature.
@@ -31,7 +30,7 @@
 }
 
 type ImageConfig struct {
-	ocispec.ImageConfig
+	specs.ImageConfig
 
 	Healthcheck *HealthConfig `json:",omitempty"` // Healthcheck describes how to check the container is healthy
 	ArgsEscaped bool          `json:",omitempty"` // True if command is already escaped (Windows specific)
@@ -46,7 +45,7 @@
 // Image is the JSON structure which describes some basic information about the image.
 // This provides the `application/vnd.oci.image.config.v1+json` mediatype when marshalled to JSON.
 type Image struct {
-	ocispec.Image
+	specs.Image
 
 	// Config defines the execution parameters which should be used as a base when running a container using the image.
 	Config ImageConfig `json:"config,omitempty"`
@@ -61,11 +60,11 @@
 	return img
 }
 
-func emptyImage() Image {
+func emptyImage(platform specs.Platform) Image {
 	img := Image{
-		Image: ocispec.Image{
-			Architecture: runtime.GOARCH,
-			OS:           runtime.GOOS,
+		Image: specs.Image{
+			Architecture: platform.Architecture,
+			OS:           platform.OS,
 		},
 	}
 	img.RootFS.Type = "layers"
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go
index 3e4617a..b96010f 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands.go
@@ -6,7 +6,6 @@
 
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/strslice"
-	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 // KeyValuePair represent an arbitrary named value (useful in slice instead of map[string] string to preserve ordering)
@@ -382,7 +381,7 @@
 	Commands   []Command
 	BaseName   string
 	SourceCode string
-	Platform   specs.Platform
+	Platform   string
 }
 
 // AddCommand to the stage
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands_runmount.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands_runmount.go
index 71030fa..569c60b 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands_runmount.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/commands_runmount.go
@@ -20,6 +20,16 @@
 	MountTypeTmpfs: {},
 }
 
+const MountSharingShared = "shared"
+const MountSharingPrivate = "private"
+const MountSharingLocked = "locked"
+
+var allowedSharingTypes = map[string]struct{}{
+	MountSharingShared:  {},
+	MountSharingPrivate: {},
+	MountSharingLocked:  {},
+}
+
 type mountsKeyT string
 
 var mountsKey = mountsKeyT("dockerfile/run/mounts")
@@ -76,12 +86,13 @@
 }
 
 type Mount struct {
-	Type     string
-	From     string
-	Source   string
-	Target   string
-	ReadOnly bool
-	CacheID  string
+	Type         string
+	From         string
+	Source       string
+	Target       string
+	ReadOnly     bool
+	CacheID      string
+	CacheSharing string
 }
 
 func parseMount(value string) (*Mount, error) {
@@ -120,7 +131,7 @@
 		switch key {
 		case "type":
 			if !isValidMountType(strings.ToLower(value)) {
-				return nil, errors.Errorf("invalid mount type %q", value)
+				return nil, errors.Errorf("unsupported mount type %q", value)
 			}
 			m.Type = strings.ToLower(value)
 		case "from":
@@ -144,6 +155,11 @@
 			roAuto = false
 		case "id":
 			m.CacheID = value
+		case "sharing":
+			if _, ok := allowedSharingTypes[strings.ToLower(value)]; !ok {
+				return nil, errors.Errorf("unsupported sharing value %q", value)
+			}
+			m.CacheSharing = strings.ToLower(value)
 		default:
 			return nil, errors.Errorf("unexpected key '%s' in '%s'", key, field)
 		}
@@ -157,5 +173,9 @@
 		}
 	}
 
+	if m.CacheSharing != "" && m.Type != MountTypeCache {
+		return nil, errors.Errorf("invalid cache sharing set for %v mount", m.Type)
+	}
+
 	return m, nil
 }
diff --git a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse.go b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse.go
index 8c8199e..d84bb43 100644
--- a/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse.go
+++ b/vendor/github.com/moby/buildkit/frontend/dockerfile/instructions/parse.go
@@ -10,7 +10,6 @@
 
 	"github.com/docker/docker/api/types/container"
 	"github.com/docker/docker/api/types/strslice"
-	"github.com/docker/docker/pkg/system"
 	"github.com/moby/buildkit/frontend/dockerfile/command"
 	"github.com/moby/buildkit/frontend/dockerfile/parser"
 	"github.com/pkg/errors"
@@ -279,13 +278,14 @@
 	if err := req.flags.Parse(); err != nil {
 		return nil, err
 	}
+
 	code := strings.TrimSpace(req.original)
 	return &Stage{
 		BaseName:   req.args[0],
 		Name:       stageName,
 		SourceCode: code,
 		Commands:   []Command{},
-		Platform:   *system.ParsePlatform(flPlatform.Value),
+		Platform:   flPlatform.Value,
 	}, nil
 
 }
diff --git a/vendor/github.com/moby/buildkit/frontend/frontend.go b/vendor/github.com/moby/buildkit/frontend/frontend.go
index f522f59..d76742d 100644
--- a/vendor/github.com/moby/buildkit/frontend/frontend.go
+++ b/vendor/github.com/moby/buildkit/frontend/frontend.go
@@ -9,6 +9,7 @@
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/solver/pb"
 	digest "github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 type Frontend interface {
@@ -17,7 +18,7 @@
 
 type FrontendLLBBridge interface {
 	Solve(ctx context.Context, req SolveRequest) (solver.CachedResult, map[string][]byte, error)
-	ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error)
+	ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error)
 	Exec(ctx context.Context, meta executor.Meta, rootfs cache.ImmutableRef, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error
 }
 
diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/client/client.go b/vendor/github.com/moby/buildkit/frontend/gateway/client/client.go
index 784925a..51c11d6 100644
--- a/vendor/github.com/moby/buildkit/frontend/gateway/client/client.go
+++ b/vendor/github.com/moby/buildkit/frontend/gateway/client/client.go
@@ -5,12 +5,13 @@
 
 	"github.com/moby/buildkit/solver/pb"
 	digest "github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 // TODO: make this take same options as LLBBridge. Add Return()
 type Client interface {
 	Solve(ctx context.Context, req SolveRequest, exporterAttr map[string][]byte, final bool) (Reference, error)
-	ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error)
+	ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error)
 	Opts() map[string]string
 	SessionID() string
 }
diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/gateway.go b/vendor/github.com/moby/buildkit/frontend/gateway/gateway.go
index 3672620..bc7698a 100644
--- a/vendor/github.com/moby/buildkit/frontend/gateway/gateway.go
+++ b/vendor/github.com/moby/buildkit/frontend/gateway/gateway.go
@@ -8,6 +8,7 @@
 	"net"
 	"os"
 	"strings"
+	"sync"
 	"time"
 
 	"github.com/docker/distribution/reference"
@@ -21,7 +22,7 @@
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/util/tracing"
 	"github.com/moby/buildkit/worker"
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/net/http2"
@@ -62,7 +63,7 @@
 	sid := session.FromContext(ctx)
 
 	_, isDevel := opts[keyDevel]
-	var img ocispec.Image
+	var img specs.Image
 	var rootFS cache.ImmutableRef
 	var readonly bool // TODO: try to switch to read-only by default.
 
@@ -94,7 +95,7 @@
 			return nil, nil, err
 		}
 
-		dgst, config, err := llbBridge.ResolveImageConfig(ctx, reference.TagNameOnly(sourceRef).String())
+		dgst, config, err := llbBridge.ResolveImageConfig(ctx, reference.TagNameOnly(sourceRef).String(), nil) // TODO:
 		if err != nil {
 			return nil, nil, err
 		}
@@ -103,9 +104,11 @@
 			return nil, nil, err
 		}
 
-		sourceRef, err = reference.WithDigest(sourceRef, dgst)
-		if err != nil {
-			return nil, nil, err
+		if dgst != "" {
+			sourceRef, err = reference.WithDigest(sourceRef, dgst)
+			if err != nil {
+				return nil, nil, err
+			}
 		}
 
 		src := llb.Image(sourceRef.String())
@@ -248,6 +251,7 @@
 }
 
 type llbBridgeForwarder struct {
+	mu           sync.Mutex
 	callCtx      context.Context
 	llbBridge    frontend.FrontendLLBBridge
 	refs         map[string]solver.Result
@@ -258,7 +262,17 @@
 
 func (lbf *llbBridgeForwarder) ResolveImageConfig(ctx context.Context, req *pb.ResolveImageConfigRequest) (*pb.ResolveImageConfigResponse, error) {
 	ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
-	dgst, dt, err := lbf.llbBridge.ResolveImageConfig(ctx, req.Ref)
+	var platform *specs.Platform
+	if p := req.Platform; p != nil {
+		platform = &specs.Platform{
+			OS:           p.OS,
+			Architecture: p.Architecture,
+			Variant:      p.Variant,
+			OSVersion:    p.OSVersion,
+			OSFeatures:   p.OSFeatures,
+		}
+	}
+	dgst, dt, err := lbf.llbBridge.ResolveImageConfig(ctx, req.Ref, platform)
 	if err != nil {
 		return nil, err
 	}
@@ -292,7 +306,9 @@
 	}
 
 	id := identity.NewID()
+	lbf.mu.Lock()
 	lbf.refs[id] = ref
+	lbf.mu.Unlock()
 	if req.Final {
 		lbf.lastRef = ref
 		lbf.exporterAttr = exp
@@ -304,7 +320,9 @@
 }
 func (lbf *llbBridgeForwarder) ReadFile(ctx context.Context, req *pb.ReadFileRequest) (*pb.ReadFileResponse, error) {
 	ctx = tracing.ContextWithSpanFromContext(ctx, lbf.callCtx)
+	lbf.mu.Lock()
 	ref, ok := lbf.refs[req.Ref]
+	lbf.mu.Unlock()
 	if !ok {
 		return nil, errors.Errorf("no such ref: %v", req.Ref)
 	}
diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.pb.go b/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.pb.go
index eb20999..bbd8531 100644
--- a/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.pb.go
+++ b/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.pb.go
@@ -45,7 +45,8 @@
 const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
 
 type ResolveImageConfigRequest struct {
-	Ref string `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"`
+	Ref      string       `protobuf:"bytes,1,opt,name=Ref,proto3" json:"Ref,omitempty"`
+	Platform *pb.Platform `protobuf:"bytes,2,opt,name=Platform" json:"Platform,omitempty"`
 }
 
 func (m *ResolveImageConfigRequest) Reset()                    { *m = ResolveImageConfigRequest{} }
@@ -60,6 +61,13 @@
 	return ""
 }
 
+func (m *ResolveImageConfigRequest) GetPlatform() *pb.Platform {
+	if m != nil {
+		return m.Platform
+	}
+	return nil
+}
+
 type ResolveImageConfigResponse struct {
 	Digest github_com_opencontainers_go_digest.Digest `protobuf:"bytes,1,opt,name=Digest,proto3,customtype=github.com/opencontainers/go-digest.Digest" json:"Digest"`
 	Config []byte                                     `protobuf:"bytes,2,opt,name=Config,proto3" json:"Config,omitempty"`
@@ -451,6 +459,16 @@
 		i = encodeVarintGateway(dAtA, i, uint64(len(m.Ref)))
 		i += copy(dAtA[i:], m.Ref)
 	}
+	if m.Platform != nil {
+		dAtA[i] = 0x12
+		i++
+		i = encodeVarintGateway(dAtA, i, uint64(m.Platform.Size()))
+		n1, err := m.Platform.MarshalTo(dAtA[i:])
+		if err != nil {
+			return 0, err
+		}
+		i += n1
+	}
 	return i, nil
 }
 
@@ -503,11 +521,11 @@
 		dAtA[i] = 0xa
 		i++
 		i = encodeVarintGateway(dAtA, i, uint64(m.Definition.Size()))
-		n1, err := m.Definition.MarshalTo(dAtA[i:])
+		n2, err := m.Definition.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n1
+		i += n2
 	}
 	if len(m.Frontend) > 0 {
 		dAtA[i] = 0x12
@@ -627,11 +645,11 @@
 		dAtA[i] = 0x1a
 		i++
 		i = encodeVarintGateway(dAtA, i, uint64(m.Range.Size()))
-		n2, err := m.Range.MarshalTo(dAtA[i:])
+		n3, err := m.Range.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n2
+		i += n3
 	}
 	return i, nil
 }
@@ -740,6 +758,10 @@
 	if l > 0 {
 		n += 1 + l + sovGateway(uint64(l))
 	}
+	if m.Platform != nil {
+		l = m.Platform.Size()
+		n += 1 + l + sovGateway(uint64(l))
+	}
 	return n
 }
 
@@ -929,6 +951,39 @@
 			}
 			m.Ref = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Platform", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowGateway
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthGateway
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.Platform == nil {
+				m.Platform = &pb.Platform{}
+			}
+			if err := m.Platform.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipGateway(dAtA[iNdEx:])
@@ -1998,45 +2053,46 @@
 func init() { proto.RegisterFile("gateway.proto", fileDescriptorGateway) }
 
 var fileDescriptorGateway = []byte{
-	// 629 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4d, 0x4f, 0xdb, 0x40,
-	0x10, 0xad, 0x63, 0x40, 0x64, 0x12, 0x3e, 0xb4, 0xaa, 0x2a, 0xe3, 0x03, 0x44, 0x56, 0x45, 0x2d,
-	0x5a, 0x6c, 0x35, 0x6d, 0x25, 0x44, 0xa5, 0x4a, 0x0d, 0x1f, 0x12, 0x15, 0x12, 0x68, 0x7b, 0xa8,
-	0xc4, 0xcd, 0x4e, 0xc6, 0x66, 0x45, 0xb2, 0xeb, 0xda, 0x1b, 0xda, 0xa8, 0x97, 0xf6, 0xe7, 0xf4,
-	0x9f, 0x70, 0xec, 0x99, 0x03, 0xaa, 0xf8, 0x25, 0x95, 0xd7, 0xeb, 0x60, 0x48, 0x49, 0xe9, 0x6d,
-	0xdf, 0x78, 0xe6, 0xed, 0x9b, 0x79, 0xb3, 0x86, 0x85, 0x38, 0x90, 0xf8, 0x25, 0x18, 0x79, 0x49,
-	0x2a, 0xa4, 0x20, 0x2b, 0x03, 0x11, 0x8e, 0xbc, 0x70, 0xc8, 0xfa, 0xbd, 0x33, 0x26, 0xbd, 0xf3,
-	0x97, 0x5e, 0x94, 0x0a, 0x2e, 0x91, 0xf7, 0xec, 0xcd, 0x98, 0xc9, 0xd3, 0x61, 0xe8, 0x75, 0xc5,
-	0xc0, 0x8f, 0x45, 0x2c, 0x7c, 0x55, 0x11, 0x0e, 0x23, 0x85, 0x14, 0x50, 0xa7, 0x82, 0xc9, 0x7e,
-	0x51, 0x49, 0xcf, 0x49, 0xfd, 0x92, 0xd4, 0xcf, 0x44, 0xff, 0x1c, 0x53, 0x3f, 0x09, 0x7d, 0x91,
-	0x64, 0x45, 0xb6, 0xb3, 0x09, 0x2b, 0x14, 0xd5, 0x87, 0x83, 0x41, 0x10, 0xe3, 0x8e, 0xe0, 0x11,
-	0x8b, 0x29, 0x7e, 0x1e, 0x62, 0x26, 0xc9, 0x32, 0x98, 0x14, 0x23, 0xcb, 0x68, 0x19, 0x6e, 0x9d,
-	0xe6, 0x47, 0xe7, 0xbb, 0x01, 0xf6, 0xdf, 0xf2, 0xb3, 0x44, 0xf0, 0x0c, 0xc9, 0x07, 0x98, 0xdb,
-	0x65, 0x31, 0x66, 0xb2, 0xa8, 0xe9, 0xb4, 0x2f, 0xae, 0xd6, 0x1e, 0x5d, 0x5e, 0xad, 0x6d, 0x54,
-	0x34, 0x89, 0x04, 0x79, 0x57, 0x70, 0x19, 0x30, 0x8e, 0x69, 0xe6, 0xc7, 0x62, 0xb3, 0xa7, 0x4a,
-	0xbc, 0xa2, 0x92, 0x6a, 0x06, 0xf2, 0x04, 0xe6, 0x0a, 0x76, 0xab, 0xd6, 0x32, 0xdc, 0x26, 0xd5,
-	0xc8, 0xb9, 0xac, 0x41, 0xf3, 0x63, 0x2e, 0xa0, 0x54, 0xe9, 0x01, 0xec, 0x62, 0xc4, 0x38, 0x93,
-	0x4c, 0x70, 0x75, 0x71, 0xa3, 0xbd, 0xe8, 0x25, 0xa1, 0x77, 0x13, 0xa5, 0x95, 0x0c, 0x62, 0xc3,
-	0xfc, 0xbe, 0x9e, 0xad, 0xa2, 0xae, 0xd3, 0x31, 0x26, 0x27, 0xd0, 0x28, 0xcf, 0x47, 0x89, 0xb4,
-	0xcc, 0x96, 0xe9, 0x36, 0xda, 0x5b, 0xde, 0xbd, 0xe6, 0x78, 0x55, 0x25, 0x5e, 0xa5, 0x74, 0x8f,
-	0xcb, 0x74, 0x44, 0xab, 0x64, 0xc4, 0x85, 0xa5, 0x83, 0x41, 0x22, 0x52, 0xb9, 0x13, 0x74, 0x4f,
-	0x91, 0x62, 0x94, 0x59, 0x33, 0x2d, 0xd3, 0xad, 0xd3, 0xbb, 0x61, 0xf2, 0x18, 0x66, 0xf7, 0x19,
-	0x0f, 0xfa, 0x16, 0xb4, 0x0c, 0x77, 0x9e, 0x16, 0x80, 0x38, 0xd0, 0xdc, 0xfb, 0x9a, 0x27, 0x62,
-	0xfa, 0x5e, 0xca, 0xd4, 0x6a, 0xa8, 0xb1, 0xdc, 0x8a, 0xd9, 0xef, 0x60, 0xf9, 0xae, 0x88, 0xdc,
-	0xc5, 0x33, 0x1c, 0x95, 0x2e, 0x9e, 0xe1, 0x28, 0xe7, 0x3f, 0x0f, 0xfa, 0x43, 0xd4, 0xed, 0x17,
-	0x60, 0xbb, 0xb6, 0x65, 0x38, 0x7b, 0xb0, 0xa0, 0x3b, 0xd2, 0x8e, 0x4e, 0xac, 0xc0, 0x84, 0x8c,
-	0xda, 0xa4, 0x0c, 0xe7, 0x1b, 0x2c, 0x51, 0x0c, 0x7a, 0xfb, 0xac, 0x8f, 0xf7, 0xee, 0x92, 0xf2,
-	0x81, 0xf5, 0xf1, 0x38, 0x90, 0xa7, 0x63, 0x1f, 0x34, 0x26, 0xdb, 0x30, 0x4b, 0x03, 0x1e, 0xa3,
-	0x65, 0x2a, 0x3b, 0x9f, 0x4e, 0x71, 0x40, 0x5d, 0x92, 0xe7, 0xd2, 0xa2, 0xc4, 0x79, 0x0b, 0xf5,
-	0x71, 0x2c, 0xdf, 0xa2, 0xa3, 0x28, 0xca, 0xb0, 0xd8, 0x48, 0x93, 0x6a, 0x94, 0xc7, 0x0f, 0x91,
-	0xc7, 0xfa, 0x6a, 0x93, 0x6a, 0xe4, 0xac, 0xc3, 0xf2, 0x8d, 0x72, 0x3d, 0x03, 0x02, 0x33, 0xbb,
-	0x81, 0x0c, 0x14, 0x43, 0x93, 0xaa, 0xb3, 0xb3, 0x00, 0x8d, 0x63, 0xc6, 0xcb, 0x97, 0xe2, 0x2c,
-	0x42, 0xf3, 0x58, 0xf0, 0xf1, 0x43, 0x68, 0xff, 0x34, 0xa1, 0x7e, 0x78, 0xd8, 0xe9, 0xa4, 0xac,
-	0x17, 0x23, 0xf9, 0x61, 0x00, 0x99, 0x7c, 0x35, 0xe4, 0xf5, 0x94, 0xae, 0xee, 0x7d, 0x94, 0xf6,
-	0x9b, 0xff, 0xac, 0xd2, 0x4d, 0x9c, 0xc0, 0xac, 0x72, 0x96, 0x3c, 0x7b, 0xe0, 0x36, 0xdb, 0xee,
-	0xbf, 0x13, 0x35, 0x77, 0x17, 0xe6, 0xcb, 0xa1, 0x91, 0x8d, 0xa9, 0xf2, 0x6e, 0xed, 0x84, 0xfd,
-	0xfc, 0x41, 0xb9, 0xfa, 0x92, 0x4f, 0x30, 0x93, 0x4f, 0x9c, 0xac, 0x4f, 0x29, 0xaa, 0x58, 0x62,
-	0x4f, 0xeb, 0xb3, 0xea, 0x55, 0xa7, 0x79, 0x71, 0xbd, 0x6a, 0xfc, 0xba, 0x5e, 0x35, 0x7e, 0x5f,
-	0xaf, 0x1a, 0xe1, 0x9c, 0xfa, 0x2f, 0xbe, 0xfa, 0x13, 0x00, 0x00, 0xff, 0xff, 0xd8, 0x21, 0xd1,
-	0x98, 0xa0, 0x05, 0x00, 0x00,
+	// 652 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x4d, 0x4f, 0xdb, 0x4a,
+	0x14, 0x7d, 0x8e, 0x01, 0x25, 0x37, 0xe6, 0x43, 0xa3, 0xa7, 0x27, 0xe3, 0x05, 0x44, 0xd6, 0x13,
+	0xcf, 0xe2, 0x15, 0x5b, 0x4d, 0x5b, 0x09, 0x51, 0xa9, 0x52, 0xc3, 0x87, 0x44, 0x85, 0x44, 0x34,
+	0x5d, 0x20, 0xb1, 0x1b, 0x27, 0x63, 0x33, 0xc2, 0x99, 0x71, 0xed, 0x09, 0x6d, 0xd4, 0x4d, 0xfb,
+	0x73, 0xfa, 0x4f, 0x58, 0x76, 0xcd, 0x02, 0x55, 0xfc, 0x92, 0xca, 0xe3, 0x71, 0x30, 0x50, 0x52,
+	0xba, 0x9b, 0x73, 0x7d, 0xef, 0x99, 0x73, 0xe7, 0xdc, 0x6b, 0x58, 0x8c, 0x89, 0xa4, 0x1f, 0xc9,
+	0xc4, 0x4f, 0x33, 0x21, 0x05, 0x5a, 0x1d, 0x89, 0x70, 0xe2, 0x87, 0x63, 0x96, 0x0c, 0xcf, 0x99,
+	0xf4, 0x2f, 0x9e, 0xfb, 0x51, 0x26, 0xb8, 0xa4, 0x7c, 0xe8, 0x6c, 0xc5, 0x4c, 0x9e, 0x8d, 0x43,
+	0x7f, 0x20, 0x46, 0x41, 0x2c, 0x62, 0x11, 0xa8, 0x8a, 0x70, 0x1c, 0x29, 0xa4, 0x80, 0x3a, 0x95,
+	0x4c, 0xce, 0xb3, 0x5a, 0x7a, 0x41, 0x1a, 0x54, 0xa4, 0x41, 0x2e, 0x92, 0x0b, 0x9a, 0x05, 0x69,
+	0x18, 0x88, 0x34, 0x2f, 0xb3, 0xdd, 0x13, 0x58, 0xc5, 0x54, 0x7d, 0x38, 0x1c, 0x91, 0x98, 0xee,
+	0x0a, 0x1e, 0xb1, 0x18, 0xd3, 0x0f, 0x63, 0x9a, 0x4b, 0xb4, 0x02, 0x26, 0xa6, 0x91, 0x6d, 0x74,
+	0x0c, 0xaf, 0x85, 0x8b, 0x23, 0xf2, 0xa0, 0xd9, 0x4f, 0x88, 0x8c, 0x44, 0x36, 0xb2, 0x1b, 0x1d,
+	0xc3, 0x6b, 0x77, 0x2d, 0x3f, 0x0d, 0xfd, 0x2a, 0x86, 0xa7, 0x5f, 0xdd, 0x2f, 0x06, 0x38, 0xbf,
+	0x62, 0xce, 0x53, 0xc1, 0x73, 0x8a, 0xde, 0xc1, 0xc2, 0x1e, 0x8b, 0x69, 0x2e, 0x4b, 0xf6, 0x5e,
+	0xf7, 0xf2, 0x7a, 0xfd, 0xaf, 0xab, 0xeb, 0xf5, 0xcd, 0x9a, 0x7a, 0x91, 0x52, 0x3e, 0x10, 0x5c,
+	0x12, 0xc6, 0x69, 0x96, 0x07, 0xb1, 0xd8, 0x1a, 0xaa, 0x12, 0xbf, 0xac, 0xc4, 0x9a, 0x01, 0xfd,
+	0x03, 0x0b, 0x25, 0xbb, 0x92, 0x64, 0x61, 0x8d, 0xdc, 0xab, 0x06, 0x58, 0xef, 0x0b, 0x01, 0x55,
+	0x3f, 0x3e, 0xc0, 0x1e, 0x8d, 0x18, 0x67, 0x92, 0x09, 0xae, 0x2e, 0x6e, 0x77, 0x97, 0x0a, 0xfd,
+	0xb7, 0x51, 0x5c, 0xcb, 0x40, 0x0e, 0x34, 0x0f, 0xb4, 0x0b, 0x8a, 0xba, 0x85, 0xa7, 0x18, 0x9d,
+	0x42, 0xbb, 0x3a, 0x1f, 0xa7, 0xd2, 0x36, 0x3b, 0xa6, 0xd7, 0xee, 0x6e, 0xfb, 0x8f, 0xda, 0xe8,
+	0xd7, 0x95, 0xf8, 0xb5, 0xd2, 0x7d, 0x2e, 0xb3, 0x09, 0xae, 0x93, 0x21, 0x0f, 0x96, 0x0f, 0x47,
+	0xa9, 0xc8, 0xe4, 0x2e, 0x19, 0x9c, 0x51, 0x4c, 0xa3, 0xdc, 0x9e, 0xeb, 0x98, 0x5e, 0x0b, 0xdf,
+	0x0f, 0xa3, 0xbf, 0x61, 0xfe, 0x80, 0x71, 0x92, 0xd8, 0xd0, 0x31, 0xbc, 0x26, 0x2e, 0x01, 0x72,
+	0xc1, 0xda, 0xff, 0x54, 0x24, 0xd2, 0xec, 0xad, 0x94, 0x99, 0xdd, 0x56, 0xcf, 0x72, 0x27, 0xe6,
+	0xbc, 0x81, 0x95, 0xfb, 0x22, 0x0a, 0xbf, 0xcf, 0xe9, 0xa4, 0xf2, 0xfb, 0x9c, 0x4e, 0x0a, 0xfe,
+	0x0b, 0x92, 0x8c, 0xa9, 0x6e, 0xbf, 0x04, 0x3b, 0x8d, 0x6d, 0xc3, 0xdd, 0x87, 0x45, 0xdd, 0x91,
+	0x76, 0xf4, 0xe1, 0xb0, 0xdc, 0x97, 0xd1, 0x78, 0x28, 0xc3, 0xfd, 0x0c, 0xcb, 0x98, 0x92, 0xe1,
+	0x01, 0x4b, 0xe8, 0xe3, 0x53, 0x57, 0xf8, 0xc0, 0x12, 0xda, 0x27, 0xf2, 0x6c, 0xea, 0x83, 0xc6,
+	0x68, 0x07, 0xe6, 0x31, 0xe1, 0x31, 0xb5, 0x4d, 0x65, 0xe7, 0xbf, 0x33, 0x1c, 0x50, 0x97, 0x14,
+	0xb9, 0xb8, 0x2c, 0x71, 0x5f, 0x43, 0x6b, 0x1a, 0x2b, 0xa6, 0xe8, 0x38, 0x8a, 0x72, 0x5a, 0x4e,
+	0xa4, 0x89, 0x35, 0x2a, 0xe2, 0x47, 0x94, 0xc7, 0xfa, 0x6a, 0x13, 0x6b, 0xe4, 0x6e, 0xc0, 0xca,
+	0xad, 0x72, 0xfd, 0x06, 0x08, 0xe6, 0xf6, 0x88, 0x24, 0x8a, 0xc1, 0xc2, 0xea, 0xec, 0x2e, 0x42,
+	0xbb, 0xcf, 0x78, 0xb5, 0x53, 0xee, 0x12, 0x58, 0x7d, 0xc1, 0xa7, 0x8b, 0xd0, 0xfd, 0x66, 0x42,
+	0xeb, 0xe8, 0xa8, 0xd7, 0xcb, 0xd8, 0x30, 0xa6, 0xe8, 0xab, 0x01, 0xe8, 0xe1, 0xd6, 0xa0, 0x97,
+	0x33, 0xba, 0x7a, 0x74, 0x7d, 0x9d, 0x57, 0x7f, 0x58, 0xa5, 0x9b, 0x38, 0x85, 0x79, 0xe5, 0x2c,
+	0xfa, 0xef, 0x89, 0xd3, 0xec, 0x78, 0xbf, 0x4f, 0xd4, 0xdc, 0x03, 0x68, 0x56, 0x8f, 0x86, 0x36,
+	0x67, 0xca, 0xbb, 0x33, 0x13, 0xce, 0xff, 0x4f, 0xca, 0xd5, 0x97, 0x9c, 0xc0, 0x5c, 0xf1, 0xe2,
+	0x68, 0x63, 0x46, 0x51, 0xcd, 0x12, 0x67, 0x56, 0x9f, 0x75, 0xaf, 0x7a, 0xd6, 0xe5, 0xcd, 0x9a,
+	0xf1, 0xfd, 0x66, 0xcd, 0xf8, 0x71, 0xb3, 0x66, 0x84, 0x0b, 0xea, 0x0f, 0xfa, 0xe2, 0x67, 0x00,
+	0x00, 0x00, 0xff, 0xff, 0xbc, 0x68, 0x1b, 0xf0, 0xca, 0x05, 0x00, 0x00,
 }
diff --git a/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.proto b/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.proto
index 55c05e4..9ba88bc 100644
--- a/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.proto
+++ b/vendor/github.com/moby/buildkit/frontend/gateway/pb/gateway.proto
@@ -18,6 +18,7 @@
 
 message ResolveImageConfigRequest {
 	string Ref = 1;
+	pb.Platform Platform = 2;
 }
 
 message ResolveImageConfigResponse {
diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/bridge.go b/vendor/github.com/moby/buildkit/solver/llbsolver/bridge.go
index 98dc2ad..8d5f46e 100644
--- a/vendor/github.com/moby/buildkit/solver/llbsolver/bridge.go
+++ b/vendor/github.com/moby/buildkit/solver/llbsolver/bridge.go
@@ -15,6 +15,7 @@
 	"github.com/moby/buildkit/util/tracing"
 	"github.com/moby/buildkit/worker"
 	digest "github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
@@ -25,6 +26,7 @@
 	ci            *remotecache.CacheImporter
 	cms           map[string]solver.CacheManager
 	cmsMu         sync.Mutex
+	platforms     []specs.Platform
 }
 
 func (b *llbBridge) Solve(ctx context.Context, req frontend.SolveRequest) (res solver.CachedResult, exp map[string][]byte, err error) {
@@ -59,7 +61,7 @@
 	}
 
 	if req.Definition != nil && req.Definition.Def != nil {
-		edge, err := Load(req.Definition, WithCacheSources(cms))
+		edge, err := Load(req.Definition, WithCacheSources(cms), RuntimePlatforms(b.platforms))
 		if err != nil {
 			return nil, nil, err
 		}
@@ -108,12 +110,12 @@
 	return err
 }
 
-func (s *llbBridge) ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error) {
+func (s *llbBridge) ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error) {
 	w, err := s.resolveWorker()
 	if err != nil {
 		return "", nil, err
 	}
-	return w.ResolveImageConfig(ctx, ref)
+	return w.ResolveImageConfig(ctx, ref, platform)
 }
 
 type lazyCacheManager struct {
diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec.go b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec.go
index ae5a322..b925227 100644
--- a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec.go
+++ b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/exec.go
@@ -11,9 +11,11 @@
 	"sort"
 	"strings"
 	"sync"
+	"time"
 
 	"github.com/boltdb/bolt"
 	"github.com/containerd/containerd/mount"
+	"github.com/docker/docker/pkg/locker"
 	"github.com/moby/buildkit/cache"
 	"github.com/moby/buildkit/cache/metadata"
 	"github.com/moby/buildkit/executor"
@@ -37,16 +39,19 @@
 	exec      executor.Executor
 	w         worker.Worker
 	numInputs int
+
+	cacheMounts map[string]*cacheRefShare
 }
 
 func NewExecOp(v solver.Vertex, op *pb.Op_Exec, cm cache.Manager, md *metadata.Store, exec executor.Executor, w worker.Worker) (solver.Op, error) {
 	return &execOp{
-		op:        op.Exec,
-		cm:        cm,
-		md:        md,
-		exec:      exec,
-		numInputs: len(v.Inputs()),
-		w:         w,
+		op:          op.Exec,
+		cm:          cm,
+		md:          md,
+		exec:        exec,
+		numInputs:   len(v.Inputs()),
+		w:           w,
+		cacheMounts: map[string]*cacheRefShare{},
 	}, nil
 }
 
@@ -165,32 +170,72 @@
 	return deps, nil
 }
 
-func (e *execOp) getRefCacheDir(ctx context.Context, ref cache.ImmutableRef, id string, m *pb.Mount) (cache.MutableRef, error) {
+func (e *execOp) getRefCacheDir(ctx context.Context, ref cache.ImmutableRef, id string, m *pb.Mount, sharing pb.CacheSharingOpt) (mref cache.MutableRef, err error) {
 
 	key := "cache-dir:" + id
 	if ref != nil {
 		key += ":" + ref.ID()
 	}
 
-	return sharedCacheRefs.get(key, func() (cache.MutableRef, error) {
-		return e.getRefCacheDirNoCache(ctx, key, ref, id, m)
-	})
+	if ref, ok := e.cacheMounts[key]; ok {
+		return ref.clone(), nil
+	}
+	defer func() {
+		if err == nil {
+			share := &cacheRefShare{MutableRef: mref, refs: map[*cacheRef]struct{}{}}
+			e.cacheMounts[key] = share
+			mref = share.clone()
+		}
+	}()
+
+	switch sharing {
+	case pb.CacheSharingOpt_SHARED:
+		return sharedCacheRefs.get(key, func() (cache.MutableRef, error) {
+			return e.getRefCacheDirNoCache(ctx, key, ref, id, m, false)
+		})
+	case pb.CacheSharingOpt_PRIVATE:
+		return e.getRefCacheDirNoCache(ctx, key, ref, id, m, false)
+	case pb.CacheSharingOpt_LOCKED:
+		return e.getRefCacheDirNoCache(ctx, key, ref, id, m, true)
+	default:
+		return nil, errors.Errorf("invalid cache sharing option: %s", sharing.String())
+	}
+
 }
 
-func (e *execOp) getRefCacheDirNoCache(ctx context.Context, key string, ref cache.ImmutableRef, id string, m *pb.Mount) (cache.MutableRef, error) {
+func (e *execOp) getRefCacheDirNoCache(ctx context.Context, key string, ref cache.ImmutableRef, id string, m *pb.Mount, block bool) (cache.MutableRef, error) {
 	makeMutable := func(cache.ImmutableRef) (cache.MutableRef, error) {
 		desc := fmt.Sprintf("cached mount %s from exec %s", m.Dest, strings.Join(e.op.Meta.Args, " "))
 		return e.cm.New(ctx, ref, cache.WithDescription(desc), cache.CachePolicyRetain)
 	}
 
-	sis, err := e.md.Search(key)
-	if err != nil {
-		return nil, err
-	}
-	for _, si := range sis {
-		if mRef, err := e.cm.GetMutable(ctx, si.ID()); err == nil {
-			logrus.Debugf("reusing ref for cache dir: %s", mRef.ID())
-			return mRef, nil
+	cacheRefsLocker.Lock(key)
+	defer cacheRefsLocker.Unlock(key)
+	for {
+		sis, err := e.md.Search(key)
+		if err != nil {
+			return nil, err
+		}
+		locked := false
+		for _, si := range sis {
+			if mRef, err := e.cm.GetMutable(ctx, si.ID()); err == nil {
+				logrus.Debugf("reusing ref for cache dir: %s", mRef.ID())
+				return mRef, nil
+			} else if errors.Cause(err) == cache.ErrLocked {
+				locked = true
+			}
+		}
+		if block && locked {
+			cacheRefsLocker.Unlock(key)
+			select {
+			case <-ctx.Done():
+				cacheRefsLocker.Lock(key)
+				return nil, ctx.Err()
+			case <-time.After(100 * time.Millisecond):
+				cacheRefsLocker.Lock(key)
+			}
+		} else {
+			break
 		}
 	}
 	mRef, err := makeMutable(ref)
@@ -287,7 +332,7 @@
 			if m.CacheOpt == nil {
 				return nil, errors.Errorf("missing cache mount options")
 			}
-			mRef, err := e.getRefCacheDir(ctx, ref, m.CacheOpt.ID, m)
+			mRef, err := e.getRefCacheDir(ctx, ref, m.CacheOpt.ID, m, m.CacheOpt.Sharing)
 			if err != nil {
 				return nil, err
 			}
@@ -418,6 +463,7 @@
 	return nil
 }
 
+var cacheRefsLocker = locker.New()
 var sharedCacheRefs = &cacheRefs{}
 
 type cacheRefs struct {
@@ -466,9 +512,11 @@
 }
 
 func (r *cacheRefShare) release(ctx context.Context) error {
-	r.main.mu.Lock()
-	defer r.main.mu.Unlock()
-	delete(r.main.shares, r.key)
+	if r.main != nil {
+		r.main.mu.Lock()
+		defer r.main.mu.Unlock()
+		delete(r.main.shares, r.key)
+	}
 	return r.MutableRef.Release(ctx)
 }
 
diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/source.go b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/source.go
index 2133a15..722861e 100644
--- a/vendor/github.com/moby/buildkit/solver/llbsolver/ops/source.go
+++ b/vendor/github.com/moby/buildkit/solver/llbsolver/ops/source.go
@@ -14,18 +14,20 @@
 const sourceCacheType = "buildkit.source.v0"
 
 type sourceOp struct {
-	mu  sync.Mutex
-	op  *pb.Op_Source
-	sm  *source.Manager
-	src source.SourceInstance
-	w   worker.Worker
+	mu       sync.Mutex
+	op       *pb.Op_Source
+	platform *pb.Platform
+	sm       *source.Manager
+	src      source.SourceInstance
+	w        worker.Worker
 }
 
-func NewSourceOp(_ solver.Vertex, op *pb.Op_Source, sm *source.Manager, w worker.Worker) (solver.Op, error) {
+func NewSourceOp(_ solver.Vertex, op *pb.Op_Source, platform *pb.Platform, sm *source.Manager, w worker.Worker) (solver.Op, error) {
 	return &sourceOp{
-		op: op,
-		sm: sm,
-		w:  w,
+		op:       op,
+		sm:       sm,
+		w:        w,
+		platform: platform,
 	}, nil
 }
 
@@ -35,7 +37,7 @@
 	if s.src != nil {
 		return s.src, nil
 	}
-	id, err := source.FromLLB(s.op)
+	id, err := source.FromLLB(s.op, s.platform)
 	if err != nil {
 		return nil, err
 	}
diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/solver.go b/vendor/github.com/moby/buildkit/solver/llbsolver/solver.go
index 460d6e1..1a03222 100644
--- a/vendor/github.com/moby/buildkit/solver/llbsolver/solver.go
+++ b/vendor/github.com/moby/buildkit/solver/llbsolver/solver.go
@@ -13,6 +13,7 @@
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/util/progress"
 	"github.com/moby/buildkit/worker"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
@@ -30,9 +31,10 @@
 	resolveWorker ResolveWorkerFunc
 	frontends     map[string]frontend.Frontend
 	ci            *remotecache.CacheImporter
+	platforms     []specs.Platform
 }
 
-func New(wc *worker.Controller, f map[string]frontend.Frontend, cacheStore solver.CacheKeyStorage, ci *remotecache.CacheImporter) *Solver {
+func New(wc *worker.Controller, f map[string]frontend.Frontend, cacheStore solver.CacheKeyStorage, ci *remotecache.CacheImporter) (*Solver, error) {
 	s := &Solver{
 		resolveWorker: defaultResolver(wc),
 		frontends:     f,
@@ -43,11 +45,18 @@
 
 	cache := solver.NewCacheManager("local", cacheStore, results)
 
+	// executing is currently only allowed on default worker
+	w, err := wc.GetDefault()
+	if err != nil {
+		return nil, err
+	}
+	s.platforms = w.Platforms()
+
 	s.solver = solver.NewSolver(solver.SolverOpt{
 		ResolveOpFunc: s.resolver(),
 		DefaultCache:  cache,
 	})
-	return s
+	return s, nil
 }
 
 func (s *Solver) resolver() solver.ResolveOpFunc {
@@ -67,6 +76,7 @@
 		resolveWorker: s.resolveWorker,
 		ci:            s.ci,
 		cms:           map[string]solver.CacheManager{},
+		platforms:     s.platforms,
 	}
 }
 
diff --git a/vendor/github.com/moby/buildkit/solver/llbsolver/vertex.go b/vendor/github.com/moby/buildkit/solver/llbsolver/vertex.go
index f7f17c1..64551ca 100644
--- a/vendor/github.com/moby/buildkit/solver/llbsolver/vertex.go
+++ b/vendor/github.com/moby/buildkit/solver/llbsolver/vertex.go
@@ -3,10 +3,12 @@
 import (
 	"strings"
 
+	"github.com/containerd/containerd/platforms"
 	"github.com/moby/buildkit/solver"
 	"github.com/moby/buildkit/solver/pb"
 	"github.com/moby/buildkit/source"
 	digest "github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
@@ -38,11 +40,44 @@
 	return v.name
 }
 
-type LoadOpt func(*solver.VertexOptions)
+type LoadOpt func(*pb.Op, *pb.OpMetadata, *solver.VertexOptions) error
 
 func WithCacheSources(cms []solver.CacheManager) LoadOpt {
-	return func(opt *solver.VertexOptions) {
+	return func(_ *pb.Op, _ *pb.OpMetadata, opt *solver.VertexOptions) error {
 		opt.CacheSources = cms
+		return nil
+	}
+}
+
+func RuntimePlatforms(p []specs.Platform) LoadOpt {
+	var defaultPlatform *pb.Platform
+	for i := range p {
+		p[i] = platforms.Normalize(p[i])
+	}
+	return func(op *pb.Op, _ *pb.OpMetadata, opt *solver.VertexOptions) error {
+		if op.Platform == nil {
+			if defaultPlatform == nil {
+				p := platforms.DefaultSpec()
+				defaultPlatform = &pb.Platform{
+					OS:           p.OS,
+					Architecture: p.Architecture,
+				}
+			}
+			op.Platform = defaultPlatform
+		}
+		if _, ok := op.Op.(*pb.Op_Exec); ok {
+			var found bool
+			for _, pp := range p {
+				if pp.OS == op.Platform.OS && pp.Architecture == op.Platform.Architecture && pp.Variant == op.Platform.Variant {
+					found = true
+					break
+				}
+			}
+			if !found {
+				return errors.Errorf("runtime execution on platform %s not supported", platforms.Format(specs.Platform{OS: op.Platform.OS, Architecture: op.Platform.Architecture, Variant: op.Platform.Variant}))
+			}
+		}
+		return nil
 	}
 }
 
@@ -67,9 +102,11 @@
 		}
 	}
 	for _, fn := range opts {
-		fn(&opt)
+		if err := fn(op, opMeta, &opt); err != nil {
+			return nil, err
+		}
 	}
-	vtx := &vertex{sys: op.Op, options: opt, digest: dgst, name: llbOpName(op)}
+	vtx := &vertex{sys: op, options: opt, digest: dgst, name: llbOpName(op)}
 	for _, in := range op.Inputs {
 		sub, err := load(in.Digest)
 		if err != nil {
@@ -129,7 +166,7 @@
 func llbOpName(op *pb.Op) string {
 	switch op := op.Op.(type) {
 	case *pb.Op_Source:
-		if id, err := source.FromLLB(op); err == nil {
+		if id, err := source.FromLLB(op, nil); err == nil {
 			if id, ok := id.(*source.LocalIdentifier); ok {
 				if len(id.IncludePatterns) == 1 {
 					return op.Source.Identifier + " (" + id.IncludePatterns[0] + ")"
diff --git a/vendor/github.com/moby/buildkit/solver/pb/ops.pb.go b/vendor/github.com/moby/buildkit/solver/pb/ops.pb.go
index d6ac7ad..5806eb7 100644
--- a/vendor/github.com/moby/buildkit/solver/pb/ops.pb.go
+++ b/vendor/github.com/moby/buildkit/solver/pb/ops.pb.go
@@ -12,6 +12,7 @@
 
 	It has these top-level messages:
 		Op
+		Platform
 		Input
 		ExecOp
 		Meta
@@ -25,7 +26,7 @@
 		OpMetadata
 		ExportCache
 		ProxyEnv
-		WorkerConstraint
+		WorkerConstraints
 		Definition
 */
 package pb
@@ -50,6 +51,7 @@
 // proto package needs to be updated.
 const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
 
+// MountType defines a type of a mount from a supported set
 type MountType int32
 
 const (
@@ -80,6 +82,34 @@
 }
 func (MountType) EnumDescriptor() ([]byte, []int) { return fileDescriptorOps, []int{0} }
 
+// CacheSharingOpt defines different sharing modes for cache mount
+type CacheSharingOpt int32
+
+const (
+	// SHARED cache mount can be used concurrently by multiple writers
+	CacheSharingOpt_SHARED CacheSharingOpt = 0
+	// PRIVATE creates a new mount if there are multiple writers
+	CacheSharingOpt_PRIVATE CacheSharingOpt = 1
+	// LOCKED pauses second writer until first one releases the mount
+	CacheSharingOpt_LOCKED CacheSharingOpt = 2
+)
+
+var CacheSharingOpt_name = map[int32]string{
+	0: "SHARED",
+	1: "PRIVATE",
+	2: "LOCKED",
+}
+var CacheSharingOpt_value = map[string]int32{
+	"SHARED":  0,
+	"PRIVATE": 1,
+	"LOCKED":  2,
+}
+
+func (x CacheSharingOpt) String() string {
+	return proto.EnumName(CacheSharingOpt_name, int32(x))
+}
+func (CacheSharingOpt) EnumDescriptor() ([]byte, []int) { return fileDescriptorOps, []int{1} }
+
 // Op represents a vertex of the LLB DAG.
 type Op struct {
 	// inputs is a set of input edges.
@@ -89,7 +119,9 @@
 	//	*Op_Source
 	//	*Op_Copy
 	//	*Op_Build
-	Op isOp_Op `protobuf_oneof:"op"`
+	Op          isOp_Op            `protobuf_oneof:"op"`
+	Platform    *Platform          `protobuf:"bytes,10,opt,name=platform" json:"platform,omitempty"`
+	Constraints *WorkerConstraints `protobuf:"bytes,11,opt,name=constraints" json:"constraints,omitempty"`
 }
 
 func (m *Op) Reset()                    { *m = Op{} }
@@ -163,6 +195,20 @@
 	return nil
 }
 
+func (m *Op) GetPlatform() *Platform {
+	if m != nil {
+		return m.Platform
+	}
+	return nil
+}
+
+func (m *Op) GetConstraints() *WorkerConstraints {
+	if m != nil {
+		return m.Constraints
+	}
+	return nil
+}
+
 // XXX_OneofFuncs is for the internal use of the proto package.
 func (*Op) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) {
 	return _Op_OneofMarshaler, _Op_OneofUnmarshaler, _Op_OneofSizer, []interface{}{
@@ -275,6 +321,55 @@
 	return n
 }
 
+// Platform is github.com/opencontainers/image-spec/specs-go/v1.Platform
+type Platform struct {
+	Architecture string   `protobuf:"bytes,1,opt,name=Architecture,proto3" json:"Architecture,omitempty"`
+	OS           string   `protobuf:"bytes,2,opt,name=OS,proto3" json:"OS,omitempty"`
+	Variant      string   `protobuf:"bytes,3,opt,name=Variant,proto3" json:"Variant,omitempty"`
+	OSVersion    string   `protobuf:"bytes,4,opt,name=OSVersion,proto3" json:"OSVersion,omitempty"`
+	OSFeatures   []string `protobuf:"bytes,5,rep,name=OSFeatures" json:"OSFeatures,omitempty"`
+}
+
+func (m *Platform) Reset()                    { *m = Platform{} }
+func (m *Platform) String() string            { return proto.CompactTextString(m) }
+func (*Platform) ProtoMessage()               {}
+func (*Platform) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{1} }
+
+func (m *Platform) GetArchitecture() string {
+	if m != nil {
+		return m.Architecture
+	}
+	return ""
+}
+
+func (m *Platform) GetOS() string {
+	if m != nil {
+		return m.OS
+	}
+	return ""
+}
+
+func (m *Platform) GetVariant() string {
+	if m != nil {
+		return m.Variant
+	}
+	return ""
+}
+
+func (m *Platform) GetOSVersion() string {
+	if m != nil {
+		return m.OSVersion
+	}
+	return ""
+}
+
+func (m *Platform) GetOSFeatures() []string {
+	if m != nil {
+		return m.OSFeatures
+	}
+	return nil
+}
+
 // Input represents an input edge for an Op.
 type Input struct {
 	// digest of the marshaled input Op
@@ -286,7 +381,7 @@
 func (m *Input) Reset()                    { *m = Input{} }
 func (m *Input) String() string            { return proto.CompactTextString(m) }
 func (*Input) ProtoMessage()               {}
-func (*Input) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{1} }
+func (*Input) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{2} }
 
 // ExecOp executes a command in a container.
 type ExecOp struct {
@@ -297,7 +392,7 @@
 func (m *ExecOp) Reset()                    { *m = ExecOp{} }
 func (m *ExecOp) String() string            { return proto.CompactTextString(m) }
 func (*ExecOp) ProtoMessage()               {}
-func (*ExecOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{2} }
+func (*ExecOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{3} }
 
 func (m *ExecOp) GetMeta() *Meta {
 	if m != nil {
@@ -327,7 +422,7 @@
 func (m *Meta) Reset()                    { *m = Meta{} }
 func (m *Meta) String() string            { return proto.CompactTextString(m) }
 func (*Meta) ProtoMessage()               {}
-func (*Meta) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{3} }
+func (*Meta) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{4} }
 
 func (m *Meta) GetArgs() []string {
 	if m != nil {
@@ -378,7 +473,7 @@
 func (m *Mount) Reset()                    { *m = Mount{} }
 func (m *Mount) String() string            { return proto.CompactTextString(m) }
 func (*Mount) ProtoMessage()               {}
-func (*Mount) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{4} }
+func (*Mount) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{5} }
 
 func (m *Mount) GetSelector() string {
 	if m != nil {
@@ -415,14 +510,18 @@
 	return nil
 }
 
+// CacheOpt defines options specific to cache mounts
 type CacheOpt struct {
+	// ID is an optional namespace for the mount
 	ID string `protobuf:"bytes,1,opt,name=ID,proto3" json:"ID,omitempty"`
+	// Sharing is the sharing mode for the mount
+	Sharing CacheSharingOpt `protobuf:"varint,2,opt,name=sharing,proto3,enum=pb.CacheSharingOpt" json:"sharing,omitempty"`
 }
 
 func (m *CacheOpt) Reset()                    { *m = CacheOpt{} }
 func (m *CacheOpt) String() string            { return proto.CompactTextString(m) }
 func (*CacheOpt) ProtoMessage()               {}
-func (*CacheOpt) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{5} }
+func (*CacheOpt) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{6} }
 
 func (m *CacheOpt) GetID() string {
 	if m != nil {
@@ -431,6 +530,13 @@
 	return ""
 }
 
+func (m *CacheOpt) GetSharing() CacheSharingOpt {
+	if m != nil {
+		return m.Sharing
+	}
+	return CacheSharingOpt_SHARED
+}
+
 // CopyOp copies files across Ops.
 type CopyOp struct {
 	Src  []*CopySource `protobuf:"bytes,1,rep,name=src" json:"src,omitempty"`
@@ -440,7 +546,7 @@
 func (m *CopyOp) Reset()                    { *m = CopyOp{} }
 func (m *CopyOp) String() string            { return proto.CompactTextString(m) }
 func (*CopyOp) ProtoMessage()               {}
-func (*CopyOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{6} }
+func (*CopyOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{7} }
 
 func (m *CopyOp) GetSrc() []*CopySource {
 	if m != nil {
@@ -465,7 +571,7 @@
 func (m *CopySource) Reset()                    { *m = CopySource{} }
 func (m *CopySource) String() string            { return proto.CompactTextString(m) }
 func (*CopySource) ProtoMessage()               {}
-func (*CopySource) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{7} }
+func (*CopySource) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{8} }
 
 func (m *CopySource) GetSelector() string {
 	if m != nil {
@@ -486,7 +592,7 @@
 func (m *SourceOp) Reset()                    { *m = SourceOp{} }
 func (m *SourceOp) String() string            { return proto.CompactTextString(m) }
 func (*SourceOp) ProtoMessage()               {}
-func (*SourceOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{8} }
+func (*SourceOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{9} }
 
 func (m *SourceOp) GetIdentifier() string {
 	if m != nil {
@@ -513,7 +619,7 @@
 func (m *BuildOp) Reset()                    { *m = BuildOp{} }
 func (m *BuildOp) String() string            { return proto.CompactTextString(m) }
 func (*BuildOp) ProtoMessage()               {}
-func (*BuildOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{9} }
+func (*BuildOp) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{10} }
 
 func (m *BuildOp) GetInputs() map[string]*BuildInput {
 	if m != nil {
@@ -544,22 +650,23 @@
 func (m *BuildInput) Reset()                    { *m = BuildInput{} }
 func (m *BuildInput) String() string            { return proto.CompactTextString(m) }
 func (*BuildInput) ProtoMessage()               {}
-func (*BuildInput) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{10} }
+func (*BuildInput) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{11} }
 
 // OpMetadata is a per-vertex metadata entry, which can be defined for arbitrary Op vertex and overridable on the run time.
 type OpMetadata struct {
 	// ignore_cache specifies to ignore the cache for this Op.
 	IgnoreCache bool `protobuf:"varint,1,opt,name=ignore_cache,json=ignoreCache,proto3" json:"ignore_cache,omitempty"`
 	// Description can be used for keeping any text fields that builder doesn't parse
-	Description      map[string]string `protobuf:"bytes,2,rep,name=description" json:"description,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
-	WorkerConstraint *WorkerConstraint `protobuf:"bytes,3,opt,name=worker_constraint,json=workerConstraint" json:"worker_constraint,omitempty"`
-	ExportCache      *ExportCache      `protobuf:"bytes,4,opt,name=export_cache,json=exportCache" json:"export_cache,omitempty"`
+	Description map[string]string `protobuf:"bytes,2,rep,name=description" json:"description,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
+	// index 3 reserved for WorkerConstraint in previous versions
+	// WorkerConstraint worker_constraint = 3;
+	ExportCache *ExportCache `protobuf:"bytes,4,opt,name=export_cache,json=exportCache" json:"export_cache,omitempty"`
 }
 
 func (m *OpMetadata) Reset()                    { *m = OpMetadata{} }
 func (m *OpMetadata) String() string            { return proto.CompactTextString(m) }
 func (*OpMetadata) ProtoMessage()               {}
-func (*OpMetadata) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{11} }
+func (*OpMetadata) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{12} }
 
 func (m *OpMetadata) GetIgnoreCache() bool {
 	if m != nil {
@@ -575,13 +682,6 @@
 	return nil
 }
 
-func (m *OpMetadata) GetWorkerConstraint() *WorkerConstraint {
-	if m != nil {
-		return m.WorkerConstraint
-	}
-	return nil
-}
-
 func (m *OpMetadata) GetExportCache() *ExportCache {
 	if m != nil {
 		return m.ExportCache
@@ -596,7 +696,7 @@
 func (m *ExportCache) Reset()                    { *m = ExportCache{} }
 func (m *ExportCache) String() string            { return proto.CompactTextString(m) }
 func (*ExportCache) ProtoMessage()               {}
-func (*ExportCache) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{12} }
+func (*ExportCache) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{13} }
 
 func (m *ExportCache) GetValue() bool {
 	if m != nil {
@@ -615,7 +715,7 @@
 func (m *ProxyEnv) Reset()                    { *m = ProxyEnv{} }
 func (m *ProxyEnv) String() string            { return proto.CompactTextString(m) }
 func (*ProxyEnv) ProtoMessage()               {}
-func (*ProxyEnv) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{13} }
+func (*ProxyEnv) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{14} }
 
 func (m *ProxyEnv) GetHttpProxy() string {
 	if m != nil {
@@ -645,17 +745,17 @@
 	return ""
 }
 
-// WorkerConstraint is experimental and likely to be changed.
-type WorkerConstraint struct {
+// WorkerConstraints defines conditions for the worker
+type WorkerConstraints struct {
 	Filter []string `protobuf:"bytes,1,rep,name=filter" json:"filter,omitempty"`
 }
 
-func (m *WorkerConstraint) Reset()                    { *m = WorkerConstraint{} }
-func (m *WorkerConstraint) String() string            { return proto.CompactTextString(m) }
-func (*WorkerConstraint) ProtoMessage()               {}
-func (*WorkerConstraint) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{14} }
+func (m *WorkerConstraints) Reset()                    { *m = WorkerConstraints{} }
+func (m *WorkerConstraints) String() string            { return proto.CompactTextString(m) }
+func (*WorkerConstraints) ProtoMessage()               {}
+func (*WorkerConstraints) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{15} }
 
-func (m *WorkerConstraint) GetFilter() []string {
+func (m *WorkerConstraints) GetFilter() []string {
 	if m != nil {
 		return m.Filter
 	}
@@ -674,7 +774,7 @@
 func (m *Definition) Reset()                    { *m = Definition{} }
 func (m *Definition) String() string            { return proto.CompactTextString(m) }
 func (*Definition) ProtoMessage()               {}
-func (*Definition) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{15} }
+func (*Definition) Descriptor() ([]byte, []int) { return fileDescriptorOps, []int{16} }
 
 func (m *Definition) GetDef() [][]byte {
 	if m != nil {
@@ -692,6 +792,7 @@
 
 func init() {
 	proto.RegisterType((*Op)(nil), "pb.Op")
+	proto.RegisterType((*Platform)(nil), "pb.Platform")
 	proto.RegisterType((*Input)(nil), "pb.Input")
 	proto.RegisterType((*ExecOp)(nil), "pb.ExecOp")
 	proto.RegisterType((*Meta)(nil), "pb.Meta")
@@ -705,9 +806,10 @@
 	proto.RegisterType((*OpMetadata)(nil), "pb.OpMetadata")
 	proto.RegisterType((*ExportCache)(nil), "pb.ExportCache")
 	proto.RegisterType((*ProxyEnv)(nil), "pb.ProxyEnv")
-	proto.RegisterType((*WorkerConstraint)(nil), "pb.WorkerConstraint")
+	proto.RegisterType((*WorkerConstraints)(nil), "pb.WorkerConstraints")
 	proto.RegisterType((*Definition)(nil), "pb.Definition")
 	proto.RegisterEnum("pb.MountType", MountType_name, MountType_value)
+	proto.RegisterEnum("pb.CacheSharingOpt", CacheSharingOpt_name, CacheSharingOpt_value)
 }
 func (m *Op) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
@@ -743,6 +845,26 @@
 		}
 		i += nn1
 	}
+	if m.Platform != nil {
+		dAtA[i] = 0x52
+		i++
+		i = encodeVarintOps(dAtA, i, uint64(m.Platform.Size()))
+		n2, err := m.Platform.MarshalTo(dAtA[i:])
+		if err != nil {
+			return 0, err
+		}
+		i += n2
+	}
+	if m.Constraints != nil {
+		dAtA[i] = 0x5a
+		i++
+		i = encodeVarintOps(dAtA, i, uint64(m.Constraints.Size()))
+		n3, err := m.Constraints.MarshalTo(dAtA[i:])
+		if err != nil {
+			return 0, err
+		}
+		i += n3
+	}
 	return i, nil
 }
 
@@ -752,11 +874,11 @@
 		dAtA[i] = 0x12
 		i++
 		i = encodeVarintOps(dAtA, i, uint64(m.Exec.Size()))
-		n2, err := m.Exec.MarshalTo(dAtA[i:])
+		n4, err := m.Exec.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n2
+		i += n4
 	}
 	return i, nil
 }
@@ -766,11 +888,11 @@
 		dAtA[i] = 0x1a
 		i++
 		i = encodeVarintOps(dAtA, i, uint64(m.Source.Size()))
-		n3, err := m.Source.MarshalTo(dAtA[i:])
+		n5, err := m.Source.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n3
+		i += n5
 	}
 	return i, nil
 }
@@ -780,11 +902,11 @@
 		dAtA[i] = 0x22
 		i++
 		i = encodeVarintOps(dAtA, i, uint64(m.Copy.Size()))
-		n4, err := m.Copy.MarshalTo(dAtA[i:])
+		n6, err := m.Copy.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n4
+		i += n6
 	}
 	return i, nil
 }
@@ -794,14 +916,71 @@
 		dAtA[i] = 0x2a
 		i++
 		i = encodeVarintOps(dAtA, i, uint64(m.Build.Size()))
-		n5, err := m.Build.MarshalTo(dAtA[i:])
+		n7, err := m.Build.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n5
+		i += n7
 	}
 	return i, nil
 }
+func (m *Platform) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalTo(dAtA)
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *Platform) MarshalTo(dAtA []byte) (int, error) {
+	var i int
+	_ = i
+	var l int
+	_ = l
+	if len(m.Architecture) > 0 {
+		dAtA[i] = 0xa
+		i++
+		i = encodeVarintOps(dAtA, i, uint64(len(m.Architecture)))
+		i += copy(dAtA[i:], m.Architecture)
+	}
+	if len(m.OS) > 0 {
+		dAtA[i] = 0x12
+		i++
+		i = encodeVarintOps(dAtA, i, uint64(len(m.OS)))
+		i += copy(dAtA[i:], m.OS)
+	}
+	if len(m.Variant) > 0 {
+		dAtA[i] = 0x1a
+		i++
+		i = encodeVarintOps(dAtA, i, uint64(len(m.Variant)))
+		i += copy(dAtA[i:], m.Variant)
+	}
+	if len(m.OSVersion) > 0 {
+		dAtA[i] = 0x22
+		i++
+		i = encodeVarintOps(dAtA, i, uint64(len(m.OSVersion)))
+		i += copy(dAtA[i:], m.OSVersion)
+	}
+	if len(m.OSFeatures) > 0 {
+		for _, s := range m.OSFeatures {
+			dAtA[i] = 0x2a
+			i++
+			l = len(s)
+			for l >= 1<<7 {
+				dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
+				l >>= 7
+				i++
+			}
+			dAtA[i] = uint8(l)
+			i++
+			i += copy(dAtA[i:], s)
+		}
+	}
+	return i, nil
+}
+
 func (m *Input) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
@@ -850,11 +1029,11 @@
 		dAtA[i] = 0xa
 		i++
 		i = encodeVarintOps(dAtA, i, uint64(m.Meta.Size()))
-		n6, err := m.Meta.MarshalTo(dAtA[i:])
+		n8, err := m.Meta.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n6
+		i += n8
 	}
 	if len(m.Mounts) > 0 {
 		for _, msg := range m.Mounts {
@@ -932,11 +1111,11 @@
 		dAtA[i] = 0x2a
 		i++
 		i = encodeVarintOps(dAtA, i, uint64(m.ProxyEnv.Size()))
-		n7, err := m.ProxyEnv.MarshalTo(dAtA[i:])
+		n9, err := m.ProxyEnv.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n7
+		i += n9
 	}
 	return i, nil
 }
@@ -999,11 +1178,11 @@
 		dAtA[i] = 0x1
 		i++
 		i = encodeVarintOps(dAtA, i, uint64(m.CacheOpt.Size()))
-		n8, err := m.CacheOpt.MarshalTo(dAtA[i:])
+		n10, err := m.CacheOpt.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n8
+		i += n10
 	}
 	return i, nil
 }
@@ -1029,6 +1208,11 @@
 		i = encodeVarintOps(dAtA, i, uint64(len(m.ID)))
 		i += copy(dAtA[i:], m.ID)
 	}
+	if m.Sharing != 0 {
+		dAtA[i] = 0x10
+		i++
+		i = encodeVarintOps(dAtA, i, uint64(m.Sharing))
+	}
 	return i, nil
 }
 
@@ -1178,11 +1362,11 @@
 				dAtA[i] = 0x12
 				i++
 				i = encodeVarintOps(dAtA, i, uint64(v.Size()))
-				n9, err := v.MarshalTo(dAtA[i:])
+				n11, err := v.MarshalTo(dAtA[i:])
 				if err != nil {
 					return 0, err
 				}
-				i += n9
+				i += n11
 			}
 		}
 	}
@@ -1190,11 +1374,11 @@
 		dAtA[i] = 0x1a
 		i++
 		i = encodeVarintOps(dAtA, i, uint64(m.Def.Size()))
-		n10, err := m.Def.MarshalTo(dAtA[i:])
+		n12, err := m.Def.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n10
+		i += n12
 	}
 	if len(m.Attrs) > 0 {
 		for k, _ := range m.Attrs {
@@ -1281,25 +1465,15 @@
 			i += copy(dAtA[i:], v)
 		}
 	}
-	if m.WorkerConstraint != nil {
-		dAtA[i] = 0x1a
-		i++
-		i = encodeVarintOps(dAtA, i, uint64(m.WorkerConstraint.Size()))
-		n11, err := m.WorkerConstraint.MarshalTo(dAtA[i:])
-		if err != nil {
-			return 0, err
-		}
-		i += n11
-	}
 	if m.ExportCache != nil {
 		dAtA[i] = 0x22
 		i++
 		i = encodeVarintOps(dAtA, i, uint64(m.ExportCache.Size()))
-		n12, err := m.ExportCache.MarshalTo(dAtA[i:])
+		n13, err := m.ExportCache.MarshalTo(dAtA[i:])
 		if err != nil {
 			return 0, err
 		}
-		i += n12
+		i += n13
 	}
 	return i, nil
 }
@@ -1374,7 +1548,7 @@
 	return i, nil
 }
 
-func (m *WorkerConstraint) Marshal() (dAtA []byte, err error) {
+func (m *WorkerConstraints) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
 	n, err := m.MarshalTo(dAtA)
@@ -1384,7 +1558,7 @@
 	return dAtA[:n], nil
 }
 
-func (m *WorkerConstraint) MarshalTo(dAtA []byte) (int, error) {
+func (m *WorkerConstraints) MarshalTo(dAtA []byte) (int, error) {
 	var i int
 	_ = i
 	var l int
@@ -1449,11 +1623,11 @@
 			dAtA[i] = 0x12
 			i++
 			i = encodeVarintOps(dAtA, i, uint64((&v).Size()))
-			n13, err := (&v).MarshalTo(dAtA[i:])
+			n14, err := (&v).MarshalTo(dAtA[i:])
 			if err != nil {
 				return 0, err
 			}
-			i += n13
+			i += n14
 		}
 	}
 	return i, nil
@@ -1480,6 +1654,14 @@
 	if m.Op != nil {
 		n += m.Op.Size()
 	}
+	if m.Platform != nil {
+		l = m.Platform.Size()
+		n += 1 + l + sovOps(uint64(l))
+	}
+	if m.Constraints != nil {
+		l = m.Constraints.Size()
+		n += 1 + l + sovOps(uint64(l))
+	}
 	return n
 }
 
@@ -1519,6 +1701,34 @@
 	}
 	return n
 }
+func (m *Platform) Size() (n int) {
+	var l int
+	_ = l
+	l = len(m.Architecture)
+	if l > 0 {
+		n += 1 + l + sovOps(uint64(l))
+	}
+	l = len(m.OS)
+	if l > 0 {
+		n += 1 + l + sovOps(uint64(l))
+	}
+	l = len(m.Variant)
+	if l > 0 {
+		n += 1 + l + sovOps(uint64(l))
+	}
+	l = len(m.OSVersion)
+	if l > 0 {
+		n += 1 + l + sovOps(uint64(l))
+	}
+	if len(m.OSFeatures) > 0 {
+		for _, s := range m.OSFeatures {
+			l = len(s)
+			n += 1 + l + sovOps(uint64(l))
+		}
+	}
+	return n
+}
+
 func (m *Input) Size() (n int) {
 	var l int
 	_ = l
@@ -1615,6 +1825,9 @@
 	if l > 0 {
 		n += 1 + l + sovOps(uint64(l))
 	}
+	if m.Sharing != 0 {
+		n += 1 + sovOps(uint64(m.Sharing))
+	}
 	return n
 }
 
@@ -1722,10 +1935,6 @@
 			n += mapEntrySize + 1 + sovOps(uint64(mapEntrySize))
 		}
 	}
-	if m.WorkerConstraint != nil {
-		l = m.WorkerConstraint.Size()
-		n += 1 + l + sovOps(uint64(l))
-	}
 	if m.ExportCache != nil {
 		l = m.ExportCache.Size()
 		n += 1 + l + sovOps(uint64(l))
@@ -1764,7 +1973,7 @@
 	return n
 }
 
-func (m *WorkerConstraint) Size() (n int) {
+func (m *WorkerConstraints) Size() (n int) {
 	var l int
 	_ = l
 	if len(m.Filter) > 0 {
@@ -1998,6 +2207,267 @@
 			}
 			m.Op = &Op_Build{v}
 			iNdEx = postIndex
+		case 10:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Platform", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowOps
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthOps
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.Platform == nil {
+				m.Platform = &Platform{}
+			}
+			if err := m.Platform.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 11:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Constraints", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowOps
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= (int(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthOps
+			}
+			postIndex := iNdEx + msglen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.Constraints == nil {
+				m.Constraints = &WorkerConstraints{}
+			}
+			if err := m.Constraints.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipOps(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if skippy < 0 {
+				return ErrInvalidLengthOps
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *Platform) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowOps
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= (uint64(b) & 0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: Platform: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: Platform: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Architecture", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowOps
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthOps
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Architecture = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field OS", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowOps
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthOps
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.OS = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 3:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Variant", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowOps
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthOps
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Variant = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 4:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field OSVersion", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowOps
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthOps
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.OSVersion = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 5:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field OSFeatures", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowOps
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= (uint64(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthOps
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.OSFeatures = append(m.OSFeatures, string(dAtA[iNdEx:postIndex]))
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipOps(dAtA[iNdEx:])
@@ -2706,6 +3176,25 @@
 			}
 			m.ID = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
+		case 2:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Sharing", wireType)
+			}
+			m.Sharing = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowOps
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.Sharing |= (CacheSharingOpt(b) & 0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
 		default:
 			iNdEx = preIndex
 			skippy, err := skipOps(dAtA[iNdEx:])
@@ -3711,39 +4200,6 @@
 			}
 			m.Description[mapkey] = mapvalue
 			iNdEx = postIndex
-		case 3:
-			if wireType != 2 {
-				return fmt.Errorf("proto: wrong wireType = %d for field WorkerConstraint", wireType)
-			}
-			var msglen int
-			for shift := uint(0); ; shift += 7 {
-				if shift >= 64 {
-					return ErrIntOverflowOps
-				}
-				if iNdEx >= l {
-					return io.ErrUnexpectedEOF
-				}
-				b := dAtA[iNdEx]
-				iNdEx++
-				msglen |= (int(b) & 0x7F) << shift
-				if b < 0x80 {
-					break
-				}
-			}
-			if msglen < 0 {
-				return ErrInvalidLengthOps
-			}
-			postIndex := iNdEx + msglen
-			if postIndex > l {
-				return io.ErrUnexpectedEOF
-			}
-			if m.WorkerConstraint == nil {
-				m.WorkerConstraint = &WorkerConstraint{}
-			}
-			if err := m.WorkerConstraint.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
-				return err
-			}
-			iNdEx = postIndex
 		case 4:
 			if wireType != 2 {
 				return fmt.Errorf("proto: wrong wireType = %d for field ExportCache", wireType)
@@ -4034,7 +4490,7 @@
 	}
 	return nil
 }
-func (m *WorkerConstraint) Unmarshal(dAtA []byte) error {
+func (m *WorkerConstraints) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	iNdEx := 0
 	for iNdEx < l {
@@ -4057,10 +4513,10 @@
 		fieldNum := int32(wire >> 3)
 		wireType := int(wire & 0x7)
 		if wireType == 4 {
-			return fmt.Errorf("proto: WorkerConstraint: wiretype end group for non-group")
+			return fmt.Errorf("proto: WorkerConstraints: wiretype end group for non-group")
 		}
 		if fieldNum <= 0 {
-			return fmt.Errorf("proto: WorkerConstraint: illegal tag %d (wire type %d)", fieldNum, wire)
+			return fmt.Errorf("proto: WorkerConstraints: illegal tag %d (wire type %d)", fieldNum, wire)
 		}
 		switch fieldNum {
 		case 1:
@@ -4423,72 +4879,81 @@
 func init() { proto.RegisterFile("ops.proto", fileDescriptorOps) }
 
 var fileDescriptorOps = []byte{
-	// 1062 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xdd, 0x6e, 0x1b, 0xc5,
-	0x17, 0xcf, 0xae, 0x3f, 0xb2, 0x7b, 0x36, 0xed, 0xdf, 0xff, 0x21, 0x2a, 0xc6, 0x94, 0xc4, 0x6c,
-	0x11, 0x72, 0xd3, 0xc6, 0x91, 0x8c, 0x84, 0x2a, 0x2e, 0x2a, 0xe2, 0x0f, 0x14, 0x83, 0x42, 0xaa,
-	0x49, 0x04, 0x97, 0x91, 0xbd, 0x1e, 0x3b, 0xab, 0x3a, 0x3b, 0xab, 0xdd, 0xd9, 0x24, 0xbe, 0x00,
-	0x89, 0x3e, 0x01, 0x12, 0x4f, 0xc1, 0x43, 0xc0, 0x75, 0x2f, 0xb9, 0x85, 0x8b, 0x82, 0xc2, 0x8b,
-	0xa0, 0x73, 0x66, 0xbc, 0xeb, 0x86, 0x22, 0xb5, 0x82, 0x2b, 0xcf, 0x9c, 0xf3, 0x3b, 0x67, 0xce,
-	0xf9, 0x9d, 0x8f, 0x35, 0xb8, 0x32, 0x4e, 0xdb, 0x71, 0x22, 0x95, 0x64, 0x76, 0x3c, 0x6e, 0xec,
-	0xce, 0x42, 0x75, 0x96, 0x8d, 0xdb, 0x81, 0x3c, 0xdf, 0x9b, 0xc9, 0x99, 0xdc, 0x23, 0xd5, 0x38,
-	0x9b, 0xd2, 0x8d, 0x2e, 0x74, 0xd2, 0x26, 0xfe, 0xcf, 0x16, 0xd8, 0x47, 0x31, 0x7b, 0x1f, 0xaa,
-	0x61, 0x14, 0x67, 0x2a, 0xad, 0x5b, 0xcd, 0x52, 0xcb, 0xeb, 0xb8, 0xed, 0x78, 0xdc, 0x1e, 0xa2,
-	0x84, 0x1b, 0x05, 0x6b, 0x42, 0x59, 0x5c, 0x89, 0xa0, 0x6e, 0x37, 0xad, 0x96, 0xd7, 0x01, 0x04,
-	0x0c, 0xae, 0x44, 0x70, 0x14, 0x1f, 0xac, 0x71, 0xd2, 0xb0, 0x0f, 0xa1, 0x9a, 0xca, 0x2c, 0x09,
-	0x44, 0xbd, 0x44, 0x98, 0x0d, 0xc4, 0x1c, 0x93, 0x84, 0x50, 0x46, 0x8b, 0x9e, 0x02, 0x19, 0x2f,
-	0xea, 0xe5, 0xc2, 0x53, 0x4f, 0xc6, 0x0b, 0xed, 0x09, 0x35, 0xec, 0x1e, 0x54, 0xc6, 0x59, 0x38,
-	0x9f, 0xd4, 0x2b, 0x04, 0xf1, 0x10, 0xd2, 0x45, 0x01, 0x61, 0xb4, 0xae, 0x5b, 0x06, 0x5b, 0xc6,
-	0xfe, 0xb7, 0x50, 0xa1, 0x38, 0xd9, 0xe7, 0x50, 0x9d, 0x84, 0x33, 0x91, 0xaa, 0xba, 0xd5, 0xb4,
-	0x5a, 0x6e, 0xb7, 0xf3, 0xfc, 0xc5, 0xf6, 0xda, 0x6f, 0x2f, 0xb6, 0x77, 0x56, 0x08, 0x91, 0xb1,
-	0x88, 0x02, 0x19, 0xa9, 0x51, 0x18, 0x89, 0x24, 0xdd, 0x9b, 0xc9, 0x5d, 0x6d, 0xd2, 0xee, 0xd3,
-	0x0f, 0x37, 0x1e, 0xd8, 0x7d, 0xa8, 0x84, 0xd1, 0x44, 0x5c, 0x51, 0xb2, 0xa5, 0xee, 0x5b, 0xc6,
-	0x95, 0x77, 0x94, 0xa9, 0x38, 0x53, 0x43, 0x54, 0x71, 0x8d, 0xf0, 0x87, 0x50, 0xd5, 0x34, 0xb0,
-	0xbb, 0x50, 0x3e, 0x17, 0x6a, 0x44, 0xcf, 0x7b, 0x1d, 0x07, 0x63, 0x3e, 0x14, 0x6a, 0xc4, 0x49,
-	0x8a, 0x0c, 0x9f, 0xcb, 0x2c, 0x52, 0x69, 0xdd, 0x2e, 0x18, 0x3e, 0x44, 0x09, 0x37, 0x0a, 0xff,
-	0x1b, 0x28, 0xa3, 0x01, 0x63, 0x50, 0x1e, 0x25, 0x33, 0x5d, 0x0a, 0x97, 0xd3, 0x99, 0xd5, 0xa0,
-	0x24, 0xa2, 0x0b, 0xb2, 0x75, 0x39, 0x1e, 0x51, 0x12, 0x5c, 0x4e, 0x88, 0x6a, 0x97, 0xe3, 0x11,
-	0xed, 0xb2, 0x54, 0x24, 0xc4, 0xab, 0xcb, 0xe9, 0xcc, 0xee, 0x83, 0x1b, 0x27, 0xf2, 0x6a, 0x71,
-	0x8a, 0xd6, 0x95, 0xa2, 0x2c, 0x4f, 0x50, 0x38, 0x88, 0x2e, 0xb8, 0x13, 0x9b, 0x93, 0xff, 0x9d,
-	0x0d, 0x15, 0x0a, 0x88, 0xb5, 0x30, 0xfd, 0x38, 0xd3, 0x4c, 0x96, 0xba, 0xcc, 0xa4, 0x0f, 0x44,
-	0x74, 0x9e, 0x3d, 0x92, 0xde, 0x00, 0x27, 0x15, 0x73, 0x11, 0x28, 0x99, 0x10, 0x57, 0x2e, 0xcf,
-	0xef, 0x18, 0xce, 0x04, 0xcb, 0xa1, 0x23, 0xa4, 0x33, 0x7b, 0x00, 0x55, 0x49, 0x1c, 0x52, 0x90,
-	0xff, 0xc0, 0xac, 0x81, 0xa0, 0xf3, 0x44, 0x8c, 0x26, 0x32, 0x9a, 0x2f, 0x28, 0x74, 0x87, 0xe7,
-	0x77, 0xf6, 0x00, 0x5c, 0x62, 0xed, 0x64, 0x11, 0x8b, 0x7a, 0xb5, 0x69, 0xb5, 0x6e, 0x77, 0x6e,
-	0xe5, 0x8c, 0xa2, 0x90, 0x17, 0x7a, 0xd6, 0x02, 0x27, 0x18, 0x05, 0x67, 0xe2, 0x28, 0x56, 0xf5,
-	0xcd, 0x82, 0x83, 0x9e, 0x91, 0xf1, 0x5c, 0xeb, 0x37, 0xc0, 0x59, 0x4a, 0xd9, 0x6d, 0xb0, 0x87,
-	0x7d, 0xdd, 0x4c, 0xdc, 0x1e, 0xf6, 0xfd, 0xc7, 0x50, 0xd5, 0x6d, 0xca, 0x9a, 0x50, 0x4a, 0x93,
-	0xc0, 0x8c, 0xca, 0xed, 0x65, 0xff, 0xea, 0x4e, 0xe7, 0xa8, 0xca, 0x73, 0xb7, 0x8b, 0xdc, 0x7d,
-	0x0e, 0x50, 0xc0, 0xfe, 0x1b, 0x8e, 0xfd, 0x1f, 0x2c, 0x70, 0x96, 0x13, 0xc6, 0xb6, 0x00, 0xc2,
-	0x89, 0x88, 0x54, 0x38, 0x0d, 0x45, 0x62, 0x02, 0x5f, 0x91, 0xb0, 0x5d, 0xa8, 0x8c, 0x94, 0x4a,
-	0x96, 0x1d, 0xf8, 0xf6, 0xea, 0x78, 0xb6, 0xf7, 0x51, 0x33, 0x88, 0x54, 0xb2, 0xe0, 0x1a, 0xd5,
-	0x78, 0x04, 0x50, 0x08, 0xb1, 0xdd, 0x9e, 0x8a, 0x85, 0xf1, 0x8a, 0x47, 0xb6, 0x09, 0x95, 0x8b,
-	0xd1, 0x3c, 0x13, 0x26, 0x28, 0x7d, 0xf9, 0xc4, 0x7e, 0x64, 0xf9, 0x3f, 0xd9, 0xb0, 0x6e, 0xc6,
-	0x95, 0x3d, 0x84, 0x75, 0x1a, 0x57, 0x13, 0xd1, 0xab, 0x33, 0x5d, 0x42, 0xd8, 0x5e, 0xbe, 0x87,
-	0x56, 0x62, 0x34, 0xae, 0xf4, 0x3e, 0x32, 0x31, 0x16, 0x5b, 0xa9, 0x34, 0x11, 0x53, 0xb3, 0x70,
-	0xa8, 0x14, 0x7d, 0x31, 0x0d, 0xa3, 0x50, 0x85, 0x32, 0xe2, 0xa8, 0x62, 0x0f, 0x97, 0x59, 0x97,
-	0xc9, 0xe3, 0x9d, 0x55, 0x8f, 0x7f, 0x4f, 0x7a, 0x08, 0xde, 0xca, 0x33, 0xaf, 0xc8, 0xfa, 0x83,
-	0xd5, 0xac, 0xcd, 0x93, 0xe4, 0x4e, 0x6f, 0xcb, 0x82, 0x85, 0x7f, 0xc1, 0xdf, 0xc7, 0x00, 0x85,
-	0xcb, 0xd7, 0xef, 0x14, 0xff, 0x47, 0x1b, 0xe0, 0x28, 0xc6, 0x1d, 0x32, 0x19, 0xd1, 0xca, 0xd9,
-	0x08, 0x67, 0x91, 0x4c, 0xc4, 0x29, 0xf5, 0x37, 0xd9, 0x3b, 0xdc, 0xd3, 0x32, 0x6a, 0x73, 0xb6,
-	0x0f, 0xde, 0x44, 0xa4, 0x41, 0x12, 0xc6, 0x48, 0x98, 0x21, 0x7d, 0x1b, 0x73, 0x2a, 0xfc, 0xb4,
-	0xfb, 0x05, 0x42, 0x73, 0xb5, 0x6a, 0xc3, 0xf6, 0xe1, 0xff, 0x97, 0x32, 0x79, 0x2a, 0x92, 0xd3,
-	0x40, 0x46, 0xa9, 0x4a, 0x46, 0x61, 0xa4, 0x4c, 0x3d, 0x36, 0xd1, 0xd1, 0xd7, 0xa4, 0xec, 0xe5,
-	0x3a, 0x5e, 0xbb, 0xbc, 0x21, 0x61, 0x1d, 0xd8, 0x10, 0x57, 0xb1, 0x4c, 0x94, 0x09, 0x54, 0x7f,
-	0x18, 0xfe, 0xa7, 0x3f, 0x31, 0x28, 0xa7, 0x60, 0xb9, 0x27, 0x8a, 0x4b, 0xe3, 0x31, 0xd4, 0x6e,
-	0xc6, 0xf5, 0x46, 0x1c, 0xdf, 0x03, 0x6f, 0xc5, 0x37, 0x02, 0xbf, 0x22, 0xa0, 0x26, 0x49, 0x5f,
-	0xfc, 0x67, 0x16, 0x38, 0xcb, 0x4d, 0xc9, 0xde, 0x03, 0x38, 0x53, 0x2a, 0x3e, 0xa5, 0x85, 0x69,
-	0x1e, 0x71, 0x51, 0x42, 0x08, 0xb6, 0x0d, 0x1e, 0x5e, 0x52, 0xa3, 0xd7, 0x0f, 0x92, 0x45, 0xaa,
-	0x01, 0xef, 0x82, 0x3b, 0xcd, 0xcd, 0xf5, 0x52, 0x74, 0xa6, 0x4b, 0xeb, 0x77, 0xc0, 0x89, 0xa4,
-	0xd1, 0xe9, 0xfd, 0xbd, 0x1e, 0x49, 0x52, 0xf9, 0x3b, 0x50, 0xbb, 0xc9, 0x21, 0xbb, 0x03, 0xd5,
-	0x69, 0x38, 0x57, 0x34, 0x54, 0xf8, 0x45, 0x30, 0x37, 0xff, 0x57, 0x0b, 0xa0, 0x18, 0x00, 0x24,
-	0x04, 0xa7, 0x03, 0x31, 0x1b, 0x7a, 0x1a, 0xe6, 0xe0, 0x9c, 0x9b, 0xba, 0x9a, 0x6a, 0xdf, 0x7d,
-	0x79, 0x68, 0xda, 0xcb, 0xb2, 0x13, 0xa5, 0xfa, 0x2b, 0xfa, 0xec, 0xf7, 0x37, 0xfa, 0x8a, 0xe6,
-	0x2f, 0x34, 0xbe, 0x80, 0x5b, 0x2f, 0xb9, 0x7b, 0xcd, 0x79, 0x2a, 0x7a, 0x6f, 0xa5, 0x62, 0x3b,
-	0x9f, 0x82, 0x9b, 0x6f, 0x77, 0xe6, 0x40, 0xb9, 0x3b, 0xfc, 0xb2, 0x5f, 0x5b, 0x63, 0x00, 0xd5,
-	0xe3, 0x41, 0x8f, 0x0f, 0x4e, 0x6a, 0x16, 0x5b, 0x87, 0xd2, 0xf1, 0xf1, 0x41, 0xcd, 0x66, 0x2e,
-	0x54, 0x7a, 0xfb, 0xbd, 0x83, 0x41, 0xad, 0x84, 0xc7, 0x93, 0xc3, 0x27, 0x9f, 0x1d, 0xd7, 0xca,
-	0xdd, 0xda, 0xf3, 0xeb, 0x2d, 0xeb, 0x97, 0xeb, 0x2d, 0xeb, 0x8f, 0xeb, 0x2d, 0xeb, 0xfb, 0x3f,
-	0xb7, 0xd6, 0xc6, 0x55, 0xfa, 0x17, 0xf4, 0xd1, 0x5f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa8, 0x76,
-	0x25, 0x54, 0x45, 0x09, 0x00, 0x00,
+	// 1203 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x4d, 0x8f, 0x1b, 0x45,
+	0x13, 0xde, 0x19, 0x7f, 0xcd, 0xd4, 0x6c, 0x36, 0x7e, 0x3b, 0x79, 0x83, 0x59, 0xc2, 0xae, 0x99,
+	0x20, 0xe4, 0x7c, 0xac, 0x57, 0x32, 0x52, 0x88, 0x38, 0x44, 0xac, 0x3f, 0xa2, 0x35, 0x21, 0x38,
+	0x6a, 0xaf, 0x96, 0x63, 0x34, 0x1e, 0xb7, 0xbd, 0xa3, 0x78, 0xa7, 0x47, 0x3d, 0xed, 0xb0, 0x3e,
+	0x80, 0x44, 0x7e, 0x01, 0x12, 0x12, 0x77, 0x7e, 0x08, 0xf7, 0x1c, 0xb9, 0xc2, 0x21, 0xa0, 0x20,
+	0xf1, 0x3b, 0x50, 0x75, 0xb7, 0x67, 0x66, 0x93, 0x20, 0x25, 0x82, 0x93, 0xbb, 0xab, 0x9e, 0x7a,
+	0xba, 0xea, 0xe9, 0x9a, 0x6a, 0x83, 0xcb, 0x93, 0xb4, 0x9d, 0x08, 0x2e, 0x39, 0xb1, 0x93, 0xc9,
+	0xf6, 0xde, 0x3c, 0x92, 0x27, 0xcb, 0x49, 0x3b, 0xe4, 0xa7, 0xfb, 0x73, 0x3e, 0xe7, 0xfb, 0xca,
+	0x35, 0x59, 0xce, 0xd4, 0x4e, 0x6d, 0xd4, 0x4a, 0x87, 0xf8, 0x3f, 0xd9, 0x60, 0x8f, 0x12, 0xf2,
+	0x01, 0x54, 0xa3, 0x38, 0x59, 0xca, 0xb4, 0x61, 0x35, 0x4b, 0x2d, 0xaf, 0xe3, 0xb6, 0x93, 0x49,
+	0x7b, 0x88, 0x16, 0x6a, 0x1c, 0xa4, 0x09, 0x65, 0x76, 0xc6, 0xc2, 0x86, 0xdd, 0xb4, 0x5a, 0x5e,
+	0x07, 0x10, 0x30, 0x38, 0x63, 0xe1, 0x28, 0x39, 0xdc, 0xa0, 0xca, 0x43, 0x3e, 0x82, 0x6a, 0xca,
+	0x97, 0x22, 0x64, 0x8d, 0x92, 0xc2, 0x6c, 0x22, 0x66, 0xac, 0x2c, 0x0a, 0x65, 0xbc, 0xc8, 0x14,
+	0xf2, 0x64, 0xd5, 0x28, 0xe7, 0x4c, 0x3d, 0x9e, 0xac, 0x34, 0x13, 0x7a, 0xc8, 0x35, 0xa8, 0x4c,
+	0x96, 0xd1, 0x62, 0xda, 0xa8, 0x28, 0x88, 0x87, 0x90, 0x2e, 0x1a, 0x14, 0x46, 0xfb, 0x48, 0x0b,
+	0x9c, 0x64, 0x11, 0xc8, 0x19, 0x17, 0xa7, 0x0d, 0xc8, 0x0f, 0x7c, 0x68, 0x6c, 0x34, 0xf3, 0x92,
+	0x4f, 0xc0, 0x0b, 0x79, 0x9c, 0x4a, 0x11, 0x44, 0xb1, 0x4c, 0x1b, 0x9e, 0x02, 0xff, 0x1f, 0xc1,
+	0x5f, 0x71, 0xf1, 0x98, 0x89, 0x5e, 0xee, 0xa4, 0x45, 0x64, 0xb7, 0x0c, 0x36, 0x4f, 0xfc, 0x1f,
+	0x2d, 0x70, 0xd6, 0xac, 0xc4, 0x87, 0xcd, 0x03, 0x11, 0x9e, 0x44, 0x92, 0x85, 0x72, 0x29, 0x58,
+	0xc3, 0x6a, 0x5a, 0x2d, 0x97, 0x9e, 0xb3, 0x91, 0x2d, 0xb0, 0x47, 0x63, 0x25, 0x94, 0x4b, 0xed,
+	0xd1, 0x98, 0x34, 0xa0, 0x76, 0x1c, 0x88, 0x28, 0x88, 0xa5, 0x52, 0xc6, 0xa5, 0xeb, 0x2d, 0xb9,
+	0x0a, 0xee, 0x68, 0x7c, 0xcc, 0x44, 0x1a, 0xf1, 0x58, 0xe9, 0xe1, 0xd2, 0xdc, 0x40, 0x76, 0x00,
+	0x46, 0xe3, 0x7b, 0x2c, 0x40, 0xd2, 0xb4, 0x51, 0x69, 0x96, 0x5a, 0x2e, 0x2d, 0x58, 0xfc, 0x6f,
+	0xa1, 0xa2, 0xee, 0x88, 0x7c, 0x0e, 0xd5, 0x69, 0x34, 0x67, 0xa9, 0xd4, 0xe9, 0x74, 0x3b, 0xcf,
+	0x9e, 0xef, 0x6e, 0xfc, 0xf6, 0x7c, 0xf7, 0x46, 0xa1, 0x19, 0x78, 0xc2, 0xe2, 0x90, 0xc7, 0x32,
+	0x88, 0x62, 0x26, 0xd2, 0xfd, 0x39, 0xdf, 0xd3, 0x21, 0xed, 0xbe, 0xfa, 0xa1, 0x86, 0x81, 0x5c,
+	0x87, 0x4a, 0x14, 0x4f, 0xd9, 0x99, 0xca, 0xbf, 0xd4, 0xbd, 0x64, 0xa8, 0xbc, 0xd1, 0x52, 0x26,
+	0x4b, 0x39, 0x44, 0x17, 0xd5, 0x08, 0x7f, 0x08, 0x55, 0xdd, 0x02, 0xe4, 0x2a, 0x94, 0x4f, 0x99,
+	0x0c, 0xd4, 0xf1, 0x5e, 0xc7, 0x41, 0x69, 0x1f, 0x30, 0x19, 0x50, 0x65, 0xc5, 0xee, 0x3a, 0xe5,
+	0x4b, 0x94, 0xde, 0xce, 0xbb, 0xeb, 0x01, 0x5a, 0xa8, 0x71, 0xf8, 0xdf, 0x40, 0x19, 0x03, 0x08,
+	0x81, 0x72, 0x20, 0xe6, 0xba, 0x0d, 0x5d, 0xaa, 0xd6, 0xa4, 0x0e, 0x25, 0x16, 0x3f, 0x51, 0xb1,
+	0x2e, 0xc5, 0x25, 0x5a, 0xc2, 0xaf, 0xa7, 0x46, 0x4c, 0x5c, 0x62, 0xdc, 0x32, 0x65, 0xc2, 0x68,
+	0xa8, 0xd6, 0xe4, 0x3a, 0xb8, 0x89, 0xe0, 0x67, 0xab, 0x47, 0x18, 0x5d, 0x29, 0x74, 0x08, 0x1a,
+	0x07, 0xf1, 0x13, 0xea, 0x24, 0x66, 0xe5, 0x7f, 0x67, 0x43, 0x45, 0x25, 0x44, 0x5a, 0x58, 0x7e,
+	0xb2, 0xd4, 0x4a, 0x96, 0xba, 0xc4, 0x94, 0x0f, 0x4a, 0xe8, 0xac, 0x7a, 0x14, 0x7d, 0x1b, 0x9c,
+	0x94, 0x2d, 0x58, 0x28, 0xb9, 0x30, 0x77, 0x9d, 0xed, 0x31, 0x9d, 0x29, 0x5e, 0x87, 0xce, 0x50,
+	0xad, 0xc9, 0x4d, 0xa8, 0x72, 0xa5, 0xa1, 0x4a, 0xf2, 0x1f, 0x94, 0x35, 0x10, 0x24, 0x17, 0x2c,
+	0x98, 0xf2, 0x78, 0xb1, 0x52, 0xa9, 0x3b, 0x34, 0xdb, 0x93, 0x9b, 0xe0, 0x2a, 0xd5, 0x8e, 0x56,
+	0x09, 0x6b, 0x54, 0x9b, 0x56, 0x6b, 0xab, 0x73, 0x21, 0x53, 0x14, 0x8d, 0x34, 0xf7, 0xe3, 0x57,
+	0x12, 0x06, 0xe1, 0x09, 0x1b, 0x25, 0xb2, 0x71, 0x39, 0xd7, 0xa0, 0x67, 0x6c, 0x34, 0xf3, 0xfa,
+	0x43, 0x70, 0xd6, 0x56, 0xec, 0xe0, 0x61, 0xdf, 0xf4, 0xb6, 0x3d, 0xec, 0x93, 0x3d, 0xa8, 0xa5,
+	0x27, 0x81, 0x88, 0xe2, 0xb9, 0x2a, 0x75, 0xab, 0x73, 0x29, 0x23, 0x19, 0x6b, 0x3b, 0x72, 0xad,
+	0x31, 0xfe, 0x5d, 0xa8, 0xea, 0x2f, 0x9a, 0x34, 0xa1, 0x94, 0x8a, 0xd0, 0x4c, 0x95, 0xad, 0xf5,
+	0xa7, 0xae, 0x87, 0x02, 0x45, 0x57, 0x26, 0x95, 0x9d, 0x4b, 0xe5, 0x53, 0x80, 0x1c, 0xf6, 0xdf,
+	0x5c, 0x89, 0xff, 0x83, 0x05, 0xce, 0x7a, 0x18, 0xe1, 0x97, 0x15, 0x4d, 0x59, 0x2c, 0xa3, 0x59,
+	0xc4, 0x84, 0xa9, 0xb3, 0x60, 0x21, 0x7b, 0x50, 0x09, 0xa4, 0x14, 0xeb, 0x86, 0x7d, 0xa7, 0x38,
+	0xc9, 0xda, 0x07, 0xe8, 0x19, 0xc4, 0x52, 0xac, 0xa8, 0x46, 0x6d, 0xdf, 0x01, 0xc8, 0x8d, 0xd8,
+	0x9d, 0x8f, 0xd9, 0xca, 0xb0, 0xe2, 0x92, 0x5c, 0x86, 0xca, 0x93, 0x60, 0xb1, 0x64, 0x26, 0x29,
+	0xbd, 0xf9, 0xd4, 0xbe, 0x63, 0xf9, 0x3f, 0xdb, 0x50, 0x33, 0x93, 0x8d, 0xdc, 0x82, 0x9a, 0x9a,
+	0x6c, 0x26, 0xa3, 0xd7, 0x57, 0xba, 0x86, 0x90, 0xfd, 0x6c, 0x64, 0x17, 0x72, 0x34, 0x54, 0x7a,
+	0x74, 0x9b, 0x1c, 0xf3, 0x01, 0x5e, 0x9a, 0xb2, 0x99, 0x99, 0xcd, 0xea, 0x2a, 0xfa, 0x6c, 0x16,
+	0xc5, 0x91, 0x8c, 0x78, 0x4c, 0xd1, 0x45, 0x6e, 0xad, 0xab, 0x2e, 0x2b, 0xc6, 0x2b, 0x45, 0xc6,
+	0x57, 0x8b, 0x1e, 0x82, 0x57, 0x38, 0xe6, 0x35, 0x55, 0x7f, 0x58, 0xac, 0xda, 0x1c, 0xa9, 0xe8,
+	0xf4, 0xc3, 0x92, 0xab, 0xf0, 0x2f, 0xf4, 0xbb, 0x0d, 0x90, 0x53, 0xbe, 0x79, 0xa7, 0xf8, 0x7f,
+	0x59, 0x00, 0xa3, 0x04, 0x47, 0xce, 0x34, 0x50, 0x13, 0x6a, 0x33, 0x9a, 0xc7, 0x5c, 0xb0, 0x47,
+	0xea, 0x73, 0x50, 0xf1, 0x0e, 0xf5, 0xb4, 0x4d, 0xb5, 0x39, 0x39, 0x00, 0x6f, 0xca, 0xd2, 0x50,
+	0x44, 0x09, 0x0a, 0x66, 0x44, 0xdf, 0xc5, 0x9a, 0x72, 0x9e, 0x76, 0x3f, 0x47, 0x68, 0xad, 0x8a,
+	0x31, 0xa4, 0x03, 0x9b, 0xec, 0x2c, 0xe1, 0x42, 0x9a, 0x53, 0xf4, 0x03, 0x78, 0x51, 0x3f, 0xa5,
+	0x68, 0x57, 0x27, 0x51, 0x8f, 0xe5, 0x9b, 0xed, 0xbb, 0x50, 0x7f, 0x99, 0xf4, 0xad, 0x04, 0xba,
+	0x06, 0x5e, 0x81, 0x1b, 0x81, 0xc7, 0x0a, 0xa8, 0x2b, 0xd4, 0x1b, 0xff, 0x29, 0xbe, 0x70, 0x66,
+	0x16, 0x92, 0xf7, 0x01, 0x4e, 0xa4, 0x4c, 0x1e, 0xa9, 0xe1, 0x68, 0x0e, 0x71, 0xd1, 0xa2, 0x10,
+	0x64, 0x17, 0x3c, 0xdc, 0xa4, 0xc6, 0xaf, 0x0f, 0x54, 0x11, 0xa9, 0x06, 0xbc, 0x07, 0xee, 0x2c,
+	0x0b, 0xd7, 0x03, 0xd0, 0x99, 0xad, 0xa3, 0xdf, 0x05, 0x27, 0xe6, 0xc6, 0xa7, 0x67, 0x75, 0x2d,
+	0xe6, 0xca, 0xe5, 0xdf, 0x84, 0xff, 0xbd, 0xf2, 0x1c, 0x93, 0x2b, 0x50, 0x9d, 0x45, 0x0b, 0xa9,
+	0x3e, 0x09, 0x1c, 0xff, 0x66, 0xe7, 0xff, 0x6a, 0x01, 0xe4, 0xed, 0x8b, 0x8a, 0x60, 0x6f, 0x23,
+	0x66, 0x53, 0xf7, 0xf2, 0x02, 0x9c, 0x53, 0x73, 0x2b, 0xe6, 0xae, 0xae, 0x9e, 0x6f, 0xf9, 0xf6,
+	0xfa, 0xd2, 0x94, 0xa6, 0xfa, 0xc9, 0x7c, 0xfa, 0xfb, 0x5b, 0x3d, 0x99, 0xd9, 0x09, 0xdb, 0xf7,
+	0xe1, 0xc2, 0x39, 0xba, 0x37, 0xfc, 0x1a, 0xf2, 0xce, 0x29, 0x5c, 0xd9, 0x8d, 0xcf, 0xc0, 0xcd,
+	0x46, 0x39, 0x71, 0xa0, 0xdc, 0x1d, 0x7e, 0xd9, 0xaf, 0x6f, 0x10, 0x80, 0xea, 0x78, 0xd0, 0xa3,
+	0x83, 0xa3, 0xba, 0x45, 0x6a, 0x50, 0x1a, 0x8f, 0x0f, 0xeb, 0x36, 0x71, 0xa1, 0xd2, 0x3b, 0xe8,
+	0x1d, 0x0e, 0xea, 0x25, 0x5c, 0x1e, 0x3d, 0x78, 0x78, 0x6f, 0x5c, 0x2f, 0xdf, 0xb8, 0x0d, 0x17,
+	0x5f, 0x9a, 0xcd, 0x2a, 0xfa, 0xf0, 0x80, 0x0e, 0x90, 0xc9, 0x83, 0xda, 0x43, 0x3a, 0x3c, 0x3e,
+	0x38, 0x1a, 0xd4, 0x2d, 0x74, 0x7c, 0x31, 0xea, 0xdd, 0x1f, 0xf4, 0xeb, 0x76, 0xb7, 0xfe, 0xec,
+	0xc5, 0x8e, 0xf5, 0xcb, 0x8b, 0x1d, 0xeb, 0x8f, 0x17, 0x3b, 0xd6, 0xf7, 0x7f, 0xee, 0x6c, 0x4c,
+	0xaa, 0xea, 0x6f, 0xe2, 0xc7, 0x7f, 0x07, 0x00, 0x00, 0xff, 0xff, 0x42, 0x80, 0x11, 0x1b, 0x66,
+	0x0a, 0x00, 0x00,
 }
diff --git a/vendor/github.com/moby/buildkit/solver/pb/ops.proto b/vendor/github.com/moby/buildkit/solver/pb/ops.proto
index 8b7af2d..6f0a524 100644
--- a/vendor/github.com/moby/buildkit/solver/pb/ops.proto
+++ b/vendor/github.com/moby/buildkit/solver/pb/ops.proto
@@ -15,7 +15,18 @@
 		SourceOp source = 3;
 		CopyOp copy = 4;
 		BuildOp build = 5;
-	 }
+	}
+	Platform platform = 10;
+	WorkerConstraints constraints = 11;
+}
+
+// Platform is github.com/opencontainers/image-spec/specs-go/v1.Platform
+message Platform {
+	string Architecture = 1;
+	string OS = 2;
+	string Variant = 3;
+	string OSVersion = 4; // unused
+	repeated string OSFeatures = 5; // unused
 }
 
 // Input represents an input edge for an Op.
@@ -54,6 +65,7 @@
 	CacheOpt cacheOpt = 20;
 }
 
+// MountType defines a type of a mount from a supported set
 enum MountType {
 	BIND = 0;
 	SECRET = 1;
@@ -62,8 +74,22 @@
 	TMPFS = 4;
 }
 
+// CacheOpt defines options specific to cache mounts
 message CacheOpt {
+	// ID is an optional namespace for the mount
 	string ID = 1;
+	// Sharing is the sharing mode for the mount 
+	CacheSharingOpt sharing = 2;
+}
+
+// CacheSharingOpt defines different sharing modes for cache mount
+enum CacheSharingOpt {
+	// SHARED cache mount can be used concurrently by multiple writers
+	SHARED = 0;
+	// PRIVATE creates a new mount if there are multiple writers
+	PRIVATE = 1;
+	// LOCKED pauses second writer until first one releases the mount
+	LOCKED = 2;
 }
 
 // CopyOp copies files across Ops.
@@ -106,8 +132,9 @@
 	// ignore_cache specifies to ignore the cache for this Op.
 	bool ignore_cache = 1;
 	// Description can be used for keeping any text fields that builder doesn't parse
-	map<string, string> description = 2;  
-	WorkerConstraint worker_constraint = 3;
+	map<string, string> description = 2; 
+	// index 3 reserved for WorkerConstraint in previous versions
+	// WorkerConstraint worker_constraint = 3;
 	ExportCache export_cache = 4;
 }
 
@@ -122,8 +149,8 @@
 	string no_proxy = 4;
 }
 
-// WorkerConstraint is experimental and likely to be changed.
-message WorkerConstraint {
+// WorkerConstraints defines conditions for the worker
+message WorkerConstraints {
 	repeated string filter = 1; // containerd-style filter
 }
 
diff --git a/vendor/github.com/moby/buildkit/source/identifier.go b/vendor/github.com/moby/buildkit/source/identifier.go
index ae6814c..a4d9f5a 100644
--- a/vendor/github.com/moby/buildkit/source/identifier.go
+++ b/vendor/github.com/moby/buildkit/source/identifier.go
@@ -8,6 +8,7 @@
 	"github.com/containerd/containerd/reference"
 	"github.com/moby/buildkit/solver/pb"
 	digest "github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
@@ -50,11 +51,20 @@
 		return nil, errors.Wrapf(errNotFound, "unknown schema %s", parts[0])
 	}
 }
-func FromLLB(op *pb.Op_Source) (Identifier, error) {
+func FromLLB(op *pb.Op_Source, platform *pb.Platform) (Identifier, error) {
 	id, err := FromString(op.Source.Identifier)
 	if err != nil {
 		return nil, err
 	}
+	if id, ok := id.(*ImageIdentifier); ok && platform != nil {
+		id.Platform = &specs.Platform{
+			OS:           platform.OS,
+			Architecture: platform.Architecture,
+			Variant:      platform.Variant,
+			OSVersion:    platform.OSVersion,
+			OSFeatures:   platform.OSFeatures,
+		}
+	}
 	if id, ok := id.(*GitIdentifier); ok {
 		for k, v := range op.Source.Attrs {
 			switch k {
@@ -136,6 +146,7 @@
 
 type ImageIdentifier struct {
 	Reference reference.Spec
+	Platform  *specs.Platform
 }
 
 func NewImageIdentifier(str string) (*ImageIdentifier, error) {
diff --git a/vendor/github.com/moby/buildkit/util/imageutil/config.go b/vendor/github.com/moby/buildkit/util/imageutil/config.go
index c9d5e39..2c2e18b 100644
--- a/vendor/github.com/moby/buildkit/util/imageutil/config.go
+++ b/vendor/github.com/moby/buildkit/util/imageutil/config.go
@@ -10,7 +10,7 @@
 	"github.com/containerd/containerd/reference"
 	"github.com/containerd/containerd/remotes"
 	digest "github.com/opencontainers/go-digest"
-	ocispec "github.com/opencontainers/image-spec/specs-go/v1"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 	"github.com/pkg/errors"
 )
 
@@ -19,16 +19,18 @@
 	content.Provider
 }
 
-func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester IngesterProvider, platform string) (digest.Digest, []byte, error) {
-	if platform == "" {
-		platform = platforms.Default()
+func Config(ctx context.Context, str string, resolver remotes.Resolver, ingester IngesterProvider, platform *specs.Platform) (digest.Digest, []byte, error) {
+	// TODO: fix containerd to take struct instead of string
+	platformStr := platforms.Default()
+	if platform != nil {
+		platformStr = platforms.Format(*platform)
 	}
 	ref, err := reference.Parse(str)
 	if err != nil {
 		return "", nil, errors.WithStack(err)
 	}
 
-	desc := ocispec.Descriptor{
+	desc := specs.Descriptor{
 		Digest: ref.Digest(),
 	}
 	if desc.Digest != "" {
@@ -56,12 +58,12 @@
 
 	handlers := []images.Handler{
 		remotes.FetchHandler(ingester, fetcher),
-		childrenConfigHandler(ingester, platform),
+		childrenConfigHandler(ingester, platformStr),
 	}
 	if err := images.Dispatch(ctx, images.Handlers(handlers...), desc); err != nil {
 		return "", nil, err
 	}
-	config, err := images.Config(ctx, ingester, desc, platform)
+	config, err := images.Config(ctx, ingester, desc, platformStr)
 	if err != nil {
 		return "", nil, err
 	}
@@ -75,10 +77,10 @@
 }
 
 func childrenConfigHandler(provider content.Provider, platform string) images.HandlerFunc {
-	return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
-		var descs []ocispec.Descriptor
+	return func(ctx context.Context, desc specs.Descriptor) ([]specs.Descriptor, error) {
+		var descs []specs.Descriptor
 		switch desc.MediaType {
-		case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
+		case images.MediaTypeDockerSchema2Manifest, specs.MediaTypeImageManifest:
 			p, err := content.ReadBlob(ctx, provider, desc)
 			if err != nil {
 				return nil, err
@@ -86,19 +88,19 @@
 
 			// TODO(stevvooe): We just assume oci manifest, for now. There may be
 			// subtle differences from the docker version.
-			var manifest ocispec.Manifest
+			var manifest specs.Manifest
 			if err := json.Unmarshal(p, &manifest); err != nil {
 				return nil, err
 			}
 
 			descs = append(descs, manifest.Config)
-		case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
+		case images.MediaTypeDockerSchema2ManifestList, specs.MediaTypeImageIndex:
 			p, err := content.ReadBlob(ctx, provider, desc)
 			if err != nil {
 				return nil, err
 			}
 
-			var index ocispec.Index
+			var index specs.Index
 			if err := json.Unmarshal(p, &index); err != nil {
 				return nil, err
 			}
@@ -118,7 +120,7 @@
 			} else {
 				descs = append(descs, index.Manifests...)
 			}
-		case images.MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig:
+		case images.MediaTypeDockerSchema2Config, specs.MediaTypeImageConfig:
 			// childless data types.
 			return nil, nil
 		default:
@@ -129,7 +131,7 @@
 	}
 }
 
-// ocispec.MediaTypeImageManifest, // TODO: detect schema1/manifest-list
+// specs.MediaTypeImageManifest, // TODO: detect schema1/manifest-list
 func DetectManifestMediaType(ra content.ReaderAt) (string, error) {
 	// TODO: schema1
 
diff --git a/vendor/github.com/moby/buildkit/vendor.conf b/vendor/github.com/moby/buildkit/vendor.conf
index 1bfc41b..26d6a3b 100644
--- a/vendor/github.com/moby/buildkit/vendor.conf
+++ b/vendor/github.com/moby/buildkit/vendor.conf
@@ -6,7 +6,7 @@
 github.com/pmezard/go-difflib v1.0.0
 golang.org/x/sys 314a259e304ff91bd6985da2a7149bbf91237993
 
-github.com/containerd/containerd 63522d9eaa5a0443d225642c4b6f4f5fdedf932b
+github.com/containerd/containerd 08f7ee9828af1783dc98cc5cc1739e915697c667
 github.com/containerd/typeurl f6943554a7e7e88b3c14aad190bf05932da84788
 golang.org/x/sync 450f422ab23cf9881c94e2db30cac0eb1b7cf80c
 github.com/sirupsen/logrus v1.0.0
diff --git a/vendor/github.com/moby/buildkit/worker/worker.go b/vendor/github.com/moby/buildkit/worker/worker.go
index 84fec1f..cd29d5e 100644
--- a/vendor/github.com/moby/buildkit/worker/worker.go
+++ b/vendor/github.com/moby/buildkit/worker/worker.go
@@ -11,16 +11,18 @@
 	"github.com/moby/buildkit/frontend"
 	"github.com/moby/buildkit/solver"
 	digest "github.com/opencontainers/go-digest"
+	specs "github.com/opencontainers/image-spec/specs-go/v1"
 )
 
 type Worker interface {
 	// ID needs to be unique in the cluster
 	ID() string
 	Labels() map[string]string
+	Platforms() []specs.Platform
 	LoadRef(id string) (cache.ImmutableRef, error)
 	// ResolveOp resolves Vertex.Sys() to Op implementation.
 	ResolveOp(v solver.Vertex, s frontend.FrontendLLBBridge) (solver.Op, error)
-	ResolveImageConfig(ctx context.Context, ref string) (digest.Digest, []byte, error)
+	ResolveImageConfig(ctx context.Context, ref string, platform *specs.Platform) (digest.Digest, []byte, error)
 	// Exec is similar to executor.Exec but without []mount.Mount
 	Exec(ctx context.Context, meta executor.Meta, rootFS cache.ImmutableRef, stdin io.ReadCloser, stdout, stderr io.WriteCloser) error
 	DiskUsage(ctx context.Context, opt client.DiskUsageInfo) ([]*client.UsageInfo, error)
@@ -33,8 +35,6 @@
 // Pre-defined label keys
 const (
 	labelPrefix      = "org.mobyproject.buildkit.worker."
-	LabelOS          = labelPrefix + "os"          // GOOS
-	LabelArch        = labelPrefix + "arch"        // GOARCH
 	LabelExecutor    = labelPrefix + "executor"    // "oci" or "containerd"
 	LabelSnapshotter = labelPrefix + "snapshotter" // containerd snapshotter name ("overlay", "native", ...)
 	LabelHostname    = labelPrefix + "hostname"