зеркало из https://github.com/microsoft/docker.git
Fix races accessing d.poolKey and d.tmpFile when pullV2Tag returns
Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
Родитель
23e68679f0
Коммит
64faec8269
|
@ -110,7 +110,6 @@ type downloadInfo struct {
|
||||||
layer distribution.ReadSeekCloser
|
layer distribution.ReadSeekCloser
|
||||||
size int64
|
size int64
|
||||||
err chan error
|
err chan error
|
||||||
out io.Writer // Download progress is written here.
|
|
||||||
poolKey string
|
poolKey string
|
||||||
broadcaster *progressreader.Broadcaster
|
broadcaster *progressreader.Broadcaster
|
||||||
}
|
}
|
||||||
|
@ -122,22 +121,6 @@ func (errVerification) Error() string { return "verification failed" }
|
||||||
func (p *v2Puller) download(di *downloadInfo) {
|
func (p *v2Puller) download(di *downloadInfo) {
|
||||||
logrus.Debugf("pulling blob %q to %s", di.digest, di.img.ID)
|
logrus.Debugf("pulling blob %q to %s", di.digest, di.img.ID)
|
||||||
|
|
||||||
di.poolKey = "layer:" + di.img.ID
|
|
||||||
broadcaster, found := p.poolAdd("pull", di.poolKey)
|
|
||||||
broadcaster.Add(di.out)
|
|
||||||
di.broadcaster = broadcaster
|
|
||||||
if found {
|
|
||||||
di.err <- nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpFile, err := ioutil.TempFile("", "GetImageBlob")
|
|
||||||
if err != nil {
|
|
||||||
di.err <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
di.tmpFile = tmpFile
|
|
||||||
|
|
||||||
blobs := p.repo.Blobs(context.Background())
|
blobs := p.repo.Blobs(context.Background())
|
||||||
|
|
||||||
desc, err := blobs.Stat(context.Background(), di.digest)
|
desc, err := blobs.Stat(context.Background(), di.digest)
|
||||||
|
@ -164,16 +147,16 @@ func (p *v2Puller) download(di *downloadInfo) {
|
||||||
|
|
||||||
reader := progressreader.New(progressreader.Config{
|
reader := progressreader.New(progressreader.Config{
|
||||||
In: ioutil.NopCloser(io.TeeReader(layerDownload, verifier)),
|
In: ioutil.NopCloser(io.TeeReader(layerDownload, verifier)),
|
||||||
Out: broadcaster,
|
Out: di.broadcaster,
|
||||||
Formatter: p.sf,
|
Formatter: p.sf,
|
||||||
Size: di.size,
|
Size: di.size,
|
||||||
NewLines: false,
|
NewLines: false,
|
||||||
ID: stringid.TruncateID(di.img.ID),
|
ID: stringid.TruncateID(di.img.ID),
|
||||||
Action: "Downloading",
|
Action: "Downloading",
|
||||||
})
|
})
|
||||||
io.Copy(tmpFile, reader)
|
io.Copy(di.tmpFile, reader)
|
||||||
|
|
||||||
broadcaster.Write(p.sf.FormatProgress(stringid.TruncateID(di.img.ID), "Verifying Checksum", nil))
|
di.broadcaster.Write(p.sf.FormatProgress(stringid.TruncateID(di.img.ID), "Verifying Checksum", nil))
|
||||||
|
|
||||||
if !verifier.Verified() {
|
if !verifier.Verified() {
|
||||||
err = fmt.Errorf("filesystem layer verification failed for digest %s", di.digest)
|
err = fmt.Errorf("filesystem layer verification failed for digest %s", di.digest)
|
||||||
|
@ -182,9 +165,9 @@ func (p *v2Puller) download(di *downloadInfo) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
broadcaster.Write(p.sf.FormatProgress(stringid.TruncateID(di.img.ID), "Download complete", nil))
|
di.broadcaster.Write(p.sf.FormatProgress(stringid.TruncateID(di.img.ID), "Download complete", nil))
|
||||||
|
|
||||||
logrus.Debugf("Downloaded %s to tempfile %s", di.img.ID, tmpFile.Name())
|
logrus.Debugf("Downloaded %s to tempfile %s", di.img.ID, di.tmpFile.Name())
|
||||||
di.layer = layerDownload
|
di.layer = layerDownload
|
||||||
|
|
||||||
di.err <- nil
|
di.err <- nil
|
||||||
|
@ -244,6 +227,16 @@ func (p *v2Puller) pullV2Tag(out io.Writer, tag, taggedName string) (verified bo
|
||||||
var layerIDs []string
|
var layerIDs []string
|
||||||
defer func() {
|
defer func() {
|
||||||
p.graph.Release(p.sessionID, layerIDs...)
|
p.graph.Release(p.sessionID, layerIDs...)
|
||||||
|
|
||||||
|
for _, d := range downloads {
|
||||||
|
p.poolRemoveWithError("pull", d.poolKey, err)
|
||||||
|
if d.tmpFile != nil {
|
||||||
|
d.tmpFile.Close()
|
||||||
|
if err := os.RemoveAll(d.tmpFile.Name()); err != nil {
|
||||||
|
logrus.Errorf("Failed to remove temp file: %s", d.tmpFile.Name())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for i := len(manifest.FSLayers) - 1; i >= 0; i-- {
|
for i := len(manifest.FSLayers) - 1; i >= 0; i-- {
|
||||||
|
@ -264,30 +257,31 @@ func (p *v2Puller) pullV2Tag(out io.Writer, tag, taggedName string) (verified bo
|
||||||
out.Write(p.sf.FormatProgress(stringid.TruncateID(img.ID), "Pulling fs layer", nil))
|
out.Write(p.sf.FormatProgress(stringid.TruncateID(img.ID), "Pulling fs layer", nil))
|
||||||
|
|
||||||
d := &downloadInfo{
|
d := &downloadInfo{
|
||||||
img: img,
|
img: img,
|
||||||
digest: manifest.FSLayers[i].BlobSum,
|
poolKey: "layer:" + img.ID,
|
||||||
|
digest: manifest.FSLayers[i].BlobSum,
|
||||||
// TODO: seems like this chan buffer solved hanging problem in go1.5,
|
// TODO: seems like this chan buffer solved hanging problem in go1.5,
|
||||||
// this can indicate some deeper problem that somehow we never take
|
// this can indicate some deeper problem that somehow we never take
|
||||||
// error from channel in loop below
|
// error from channel in loop below
|
||||||
err: make(chan error, 1),
|
err: make(chan error, 1),
|
||||||
out: pipeWriter,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tmpFile, err := ioutil.TempFile("", "GetImageBlob")
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
d.tmpFile = tmpFile
|
||||||
|
|
||||||
downloads = append(downloads, d)
|
downloads = append(downloads, d)
|
||||||
|
|
||||||
go p.download(d)
|
broadcaster, found := p.poolAdd("pull", d.poolKey)
|
||||||
}
|
broadcaster.Add(pipeWriter)
|
||||||
|
d.broadcaster = broadcaster
|
||||||
// run clean for all downloads to prevent leftovers
|
if found {
|
||||||
for _, d := range downloads {
|
d.err <- nil
|
||||||
defer func(d *downloadInfo) {
|
} else {
|
||||||
p.poolRemoveWithError("pull", d.poolKey, err)
|
go p.download(d)
|
||||||
if d.tmpFile != nil {
|
}
|
||||||
d.tmpFile.Close()
|
|
||||||
if err := os.RemoveAll(d.tmpFile.Name()); err != nil {
|
|
||||||
logrus.Errorf("Failed to remove temp file: %s", d.tmpFile.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}(d)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagUpdated bool
|
var tagUpdated bool
|
||||||
|
|
Загрузка…
Ссылка в новой задаче