@@ -601,15 +601,18 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
601601 }
602602
603603 configChan := make (chan []byte , 1 )
604- errChan := make (chan error , 1 )
604+ configErrChan := make (chan error , 1 )
605+ layerErrChan := make (chan error , 1 )
606+ downloadsDone := make (chan struct {})
605607 var cancel func ()
606608 ctx , cancel = context .WithCancel (ctx )
609+ defer cancel ()
607610
608611 // Pull the image config
609612 go func () {
610613 configJSON , err := p .pullSchema2Config (ctx , target .Digest )
611614 if err != nil {
612- errChan <- ImageConfigPullError {Err : err }
615+ configErrChan <- ImageConfigPullError {Err : err }
613616 cancel ()
614617 return
615618 }
@@ -620,6 +623,7 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
620623 configJSON []byte // raw serialized image config
621624 downloadedRootFS * image.RootFS // rootFS from registered layers
622625 configRootFS * image.RootFS // rootFS from configuration
626+ release func () // release resources from rootFS download
623627 )
624628
625629 // https://github.com/docker/docker/issues/24766 - Err on the side of caution,
@@ -631,7 +635,7 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
631635 // check to block Windows images being pulled on Linux is implemented, it
632636 // may be necessary to perform the same type of serialisation.
633637 if runtime .GOOS == "windows" {
634- configJSON , configRootFS , err = receiveConfig (p .config .ImageStore , configChan , errChan )
638+ configJSON , configRootFS , err = receiveConfig (p .config .ImageStore , configChan , configErrChan )
635639 if err != nil {
636640 return "" , "" , err
637641 }
@@ -642,41 +646,52 @@ func (p *v2Puller) pullSchema2(ctx context.Context, ref reference.Named, mfst *s
642646 }
643647
644648 if p .config .DownloadManager != nil {
645- downloadRootFS := * image .NewRootFS ()
646- rootFS , release , err := p .config .DownloadManager .Download (ctx , downloadRootFS , descriptors , p .config .ProgressOutput )
647- if err != nil {
648- if configJSON != nil {
649- // Already received the config
650- return "" , "" , err
651- }
652- select {
653- case err = <- errChan :
654- return "" , "" , err
655- default :
656- cancel ()
657- select {
658- case <- configChan :
659- case <- errChan :
660- }
661- return "" , "" , err
649+ go func () {
650+ var (
651+ err error
652+ rootFS image.RootFS
653+ )
654+ downloadRootFS := * image .NewRootFS ()
655+ rootFS , release , err = p .config .DownloadManager .Download (ctx , downloadRootFS , descriptors , p .config .ProgressOutput )
656+ if err != nil {
657+ // Intentionally do not cancel the config download here
658+ // as the error from config download (if there is one)
659+ // is more interesting than the layer download error
660+ layerErrChan <- err
661+ return
662662 }
663- }
664- if release != nil {
665- defer release ()
666- }
667663
668- downloadedRootFS = & rootFS
664+ downloadedRootFS = & rootFS
665+ close (downloadsDone )
666+ }()
667+ } else {
668+ // We have nothing to download
669+ close (downloadsDone )
669670 }
670671
671672 if configJSON == nil {
672- configJSON , configRootFS , err = receiveConfig (p .config .ImageStore , configChan , errChan )
673+ configJSON , configRootFS , err = receiveConfig (p .config .ImageStore , configChan , configErrChan )
674+ if err == nil && configRootFS == nil {
675+ err = errRootFSInvalid
676+ }
673677 if err != nil {
678+ cancel ()
679+ select {
680+ case <- downloadsDone :
681+ case <- layerErrChan :
682+ }
674683 return "" , "" , err
675684 }
685+ }
676686
677- if configRootFS == nil {
678- return "" , "" , errRootFSInvalid
679- }
687+ select {
688+ case <- downloadsDone :
689+ case err = <- layerErrChan :
690+ return "" , "" , err
691+ }
692+
693+ if release != nil {
694+ defer release ()
680695 }
681696
682697 if downloadedRootFS != nil {
0 commit comments