From f8454e82b61b7e291fc246a68886e79fdb2b43c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Tue, 22 Feb 2022 00:35:21 +0100 Subject: [PATCH 1/6] Remove a redundant check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit err must be nil at that point. This also un-indents the success case, so that it proceeds as a straight-line code. Signed-off-by: Miloslav Trmač --- layers.go | 148 +++++++++++++++++++++++++++--------------------------- 1 file changed, 73 insertions(+), 75 deletions(-) diff --git a/layers.go b/layers.go index 34d27ffa33..9cfe22e1d9 100644 --- a/layers.go +++ b/layers.go @@ -813,88 +813,86 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab return nil, -1, err } } - if err == nil { - layer = &Layer{ - ID: id, - Parent: parent, - Names: names, - MountLabel: mountLabel, - Metadata: templateMetadata, - Created: time.Now().UTC(), - CompressedDigest: templateCompressedDigest, - CompressedSize: templateCompressedSize, - UncompressedDigest: templateUncompressedDigest, - UncompressedSize: templateUncompressedSize, - CompressionType: templateCompressionType, - UIDs: templateUIDs, - GIDs: templateGIDs, - Flags: make(map[string]interface{}), - UIDMap: copyIDMap(moreOptions.UIDMap), - GIDMap: copyIDMap(moreOptions.GIDMap), - BigDataNames: []string{}, - } - r.layers = append(r.layers, layer) - r.idindex.Add(id) - r.byid[id] = layer - for _, name := range names { - r.byname[name] = layer - } - for flag, value := range flags { - layer.Flags[flag] = value - } - savedIncompleteLayer := false - if diff != nil { - layer.Flags[incompleteFlag] = true - err = r.Save() - if err != nil { - // We don't have a record of this layer, but at least - // try to clean it up underneath us. - if err2 := r.driver.Remove(id); err2 != nil { - logrus.Errorf("While recovering from a failure saving incomplete layer metadata, error deleting layer %#v: %v", id, err2) - } - return nil, -1, err - } - savedIncompleteLayer = true - size, err = r.applyDiffWithOptions(layer.ID, moreOptions, diff) - if err != nil { - if err2 := r.Delete(layer.ID); err2 != nil { - // Either a driver error or an error saving. - // We now have a layer that's been marked for - // deletion but which we failed to remove. - logrus.Errorf("While recovering from a failure applying layer diff, error deleting layer %#v: %v", layer.ID, err2) - } - return nil, -1, err - } - delete(layer.Flags, incompleteFlag) - } else { - // applyDiffWithOptions in the `diff != nil` case handles this bit for us - if layer.CompressedDigest != "" { - r.bycompressedsum[layer.CompressedDigest] = append(r.bycompressedsum[layer.CompressedDigest], layer.ID) - } - if layer.UncompressedDigest != "" { - r.byuncompressedsum[layer.UncompressedDigest] = append(r.byuncompressedsum[layer.UncompressedDigest], layer.ID) + layer = &Layer{ + ID: id, + Parent: parent, + Names: names, + MountLabel: mountLabel, + Metadata: templateMetadata, + Created: time.Now().UTC(), + CompressedDigest: templateCompressedDigest, + CompressedSize: templateCompressedSize, + UncompressedDigest: templateUncompressedDigest, + UncompressedSize: templateUncompressedSize, + CompressionType: templateCompressionType, + UIDs: templateUIDs, + GIDs: templateGIDs, + Flags: make(map[string]interface{}), + UIDMap: copyIDMap(moreOptions.UIDMap), + GIDMap: copyIDMap(moreOptions.GIDMap), + BigDataNames: []string{}, + } + r.layers = append(r.layers, layer) + r.idindex.Add(id) + r.byid[id] = layer + for _, name := range names { + r.byname[name] = layer + } + for flag, value := range flags { + layer.Flags[flag] = value + } + savedIncompleteLayer := false + if diff != nil { + layer.Flags[incompleteFlag] = true + err = r.Save() + if err != nil { + // We don't have a record of this layer, but at least + // try to clean it up underneath us. + if err2 := r.driver.Remove(id); err2 != nil { + logrus.Errorf("While recovering from a failure saving incomplete layer metadata, error deleting layer %#v: %v", id, err2) } + return nil, -1, err } - err = r.Save() + savedIncompleteLayer = true + size, err = r.applyDiffWithOptions(layer.ID, moreOptions, diff) if err != nil { - if savedIncompleteLayer { - if err2 := r.Delete(layer.ID); err2 != nil { - // Either a driver error or an error saving. - // We now have a layer that's been marked for - // deletion but which we failed to remove. - logrus.Errorf("While recovering from a failure saving finished layer metadata, error deleting layer %#v: %v", layer.ID, err2) - } - } else { - // We don't have a record of this layer, but at least - // try to clean it up underneath us. - if err2 := r.driver.Remove(id); err2 != nil { - logrus.Errorf("While recovering from a failure saving finished layer metadata, error deleting layer %#v in graph driver: %v", id, err2) - } + if err2 := r.Delete(layer.ID); err2 != nil { + // Either a driver error or an error saving. + // We now have a layer that's been marked for + // deletion but which we failed to remove. + logrus.Errorf("While recovering from a failure applying layer diff, error deleting layer %#v: %v", layer.ID, err2) } return nil, -1, err } - layer = copyLayer(layer) + delete(layer.Flags, incompleteFlag) + } else { + // applyDiffWithOptions in the `diff != nil` case handles this bit for us + if layer.CompressedDigest != "" { + r.bycompressedsum[layer.CompressedDigest] = append(r.bycompressedsum[layer.CompressedDigest], layer.ID) + } + if layer.UncompressedDigest != "" { + r.byuncompressedsum[layer.UncompressedDigest] = append(r.byuncompressedsum[layer.UncompressedDigest], layer.ID) + } + } + err = r.Save() + if err != nil { + if savedIncompleteLayer { + if err2 := r.Delete(layer.ID); err2 != nil { + // Either a driver error or an error saving. + // We now have a layer that's been marked for + // deletion but which we failed to remove. + logrus.Errorf("While recovering from a failure saving finished layer metadata, error deleting layer %#v: %v", layer.ID, err2) + } + } else { + // We don't have a record of this layer, but at least + // try to clean it up underneath us. + if err2 := r.driver.Remove(id); err2 != nil { + logrus.Errorf("While recovering from a failure saving finished layer metadata, error deleting layer %#v in graph driver: %v", id, err2) + } + } + return nil, -1, err } + layer = copyLayer(layer) return layer, size, err } From 99789d119a7786ef56577837749d1820dbbcea53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Tue, 22 Feb 2022 01:01:41 +0100 Subject: [PATCH 2/6] Always save an "incomplete" layer record first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For now, this only causes two redundant saves for non-tarball layers, which is not useful; but it will allow us to build infrastructure for saving the incomplete record much earlier. Signed-off-by: Miloslav Trmač --- layers.go | 42 ++++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/layers.go b/layers.go index 9cfe22e1d9..dc896ba8f4 100644 --- a/layers.go +++ b/layers.go @@ -841,19 +841,17 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab for flag, value := range flags { layer.Flags[flag] = value } - savedIncompleteLayer := false - if diff != nil { - layer.Flags[incompleteFlag] = true - err = r.Save() - if err != nil { - // We don't have a record of this layer, but at least - // try to clean it up underneath us. - if err2 := r.driver.Remove(id); err2 != nil { - logrus.Errorf("While recovering from a failure saving incomplete layer metadata, error deleting layer %#v: %v", id, err2) - } - return nil, -1, err + layer.Flags[incompleteFlag] = true + err = r.Save() + if err != nil { + // We don't have a record of this layer, but at least + // try to clean it up underneath us. + if err2 := r.driver.Remove(id); err2 != nil { + logrus.Errorf("While recovering from a failure saving incomplete layer metadata, error deleting layer %#v: %v", id, err2) } - savedIncompleteLayer = true + return nil, -1, err + } + if diff != nil { size, err = r.applyDiffWithOptions(layer.ID, moreOptions, diff) if err != nil { if err2 := r.Delete(layer.ID); err2 != nil { @@ -864,7 +862,6 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab } return nil, -1, err } - delete(layer.Flags, incompleteFlag) } else { // applyDiffWithOptions in the `diff != nil` case handles this bit for us if layer.CompressedDigest != "" { @@ -874,21 +871,14 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab r.byuncompressedsum[layer.UncompressedDigest] = append(r.byuncompressedsum[layer.UncompressedDigest], layer.ID) } } + delete(layer.Flags, incompleteFlag) err = r.Save() if err != nil { - if savedIncompleteLayer { - if err2 := r.Delete(layer.ID); err2 != nil { - // Either a driver error or an error saving. - // We now have a layer that's been marked for - // deletion but which we failed to remove. - logrus.Errorf("While recovering from a failure saving finished layer metadata, error deleting layer %#v: %v", layer.ID, err2) - } - } else { - // We don't have a record of this layer, but at least - // try to clean it up underneath us. - if err2 := r.driver.Remove(id); err2 != nil { - logrus.Errorf("While recovering from a failure saving finished layer metadata, error deleting layer %#v in graph driver: %v", id, err2) - } + if err2 := r.Delete(layer.ID); err2 != nil { + // Either a driver error or an error saving. + // We now have a layer that's been marked for + // deletion but which we failed to remove. + logrus.Errorf("While recovering from a failure saving finished layer metadata, error deleting layer %#v: %v", layer.ID, err2) } return nil, -1, err } From e25b3d4baf79477811045c0012afd0bec75fba93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Tue, 22 Feb 2022 01:04:22 +0100 Subject: [PATCH 3/6] Always use layerStore.Delete when recovering from failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... so that we also remove the layer from layerStore.layers and the like. Signed-off-by: Miloslav Trmač --- layers.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/layers.go b/layers.go index dc896ba8f4..525004ac17 100644 --- a/layers.go +++ b/layers.go @@ -844,9 +844,10 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab layer.Flags[incompleteFlag] = true err = r.Save() if err != nil { - // We don't have a record of this layer, but at least - // try to clean it up underneath us. - if err2 := r.driver.Remove(id); err2 != nil { + // We don't have a presistent record of this layer, but + // try to remove both the driver’s data as well as + // the in-memory layer record. + if err2 := r.Delete(layer.ID); err2 != nil { logrus.Errorf("While recovering from a failure saving incomplete layer metadata, error deleting layer %#v: %v", id, err2) } return nil, -1, err From ce3c7ffbd2e644f86d74cc7a51a35adb20fca6ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Tue, 22 Feb 2022 16:49:32 +0100 Subject: [PATCH 4/6] Don't use named return values in layerStore.Put MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We will need want to refer to "layer" in a defer block, in order to delete that layer. That doesn't work with "layer" being a named return value, because a (return nil, -1, ...) sets "layer" to nil. So, turn "layer" into a local variable, and use an unnamed return value. And beause all return values must be named, or unnamed, consistently, turn "size" and "err" also into local variables. Then decrease the scope of the "size" and "err" local variables to simplify understanding the code a bit. Signed-off-by: Miloslav Trmač --- layers.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/layers.go b/layers.go index 525004ac17..cea38a3c84 100644 --- a/layers.go +++ b/layers.go @@ -692,11 +692,10 @@ func (r *layerStore) PutAdditionalLayer(id string, parentLayer *Layer, names []s return copyLayer(layer), nil } -func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, flags map[string]interface{}, diff io.Reader) (layer *Layer, size int64, err error) { +func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, flags map[string]interface{}, diff io.Reader) (*Layer, int64, error) { if !r.IsReadWrite() { return nil, -1, errors.Wrapf(ErrStoreIsReadOnly, "not allowed to create new layers at %q", r.layerspath()) } - size = -1 if err := os.MkdirAll(r.rundir, 0700); err != nil { return nil, -1, err } @@ -769,24 +768,24 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab IDMappings: idMappings, } if moreOptions.TemplateLayer != "" { - if err = r.driver.CreateFromTemplate(id, moreOptions.TemplateLayer, templateIDMappings, parent, parentMappings, &opts, writeable); err != nil { + if err := r.driver.CreateFromTemplate(id, moreOptions.TemplateLayer, templateIDMappings, parent, parentMappings, &opts, writeable); err != nil { return nil, -1, errors.Wrapf(err, "error creating copy of template layer %q with ID %q", moreOptions.TemplateLayer, id) } oldMappings = templateIDMappings } else { if writeable { - if err = r.driver.CreateReadWrite(id, parent, &opts); err != nil { + if err := r.driver.CreateReadWrite(id, parent, &opts); err != nil { return nil, -1, errors.Wrapf(err, "error creating read-write layer with ID %q", id) } } else { - if err = r.driver.Create(id, parent, &opts); err != nil { + if err := r.driver.Create(id, parent, &opts); err != nil { return nil, -1, errors.Wrapf(err, "error creating layer with ID %q", id) } } oldMappings = parentMappings } if !reflect.DeepEqual(oldMappings.UIDs(), idMappings.UIDs()) || !reflect.DeepEqual(oldMappings.GIDs(), idMappings.GIDs()) { - if err = r.driver.UpdateLayerIDMap(id, oldMappings, idMappings, mountLabel); err != nil { + if err := r.driver.UpdateLayerIDMap(id, oldMappings, idMappings, mountLabel); err != nil { // We don't have a record of this layer, but at least // try to clean it up underneath us. if err2 := r.driver.Remove(id); err2 != nil { @@ -804,7 +803,7 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab } return nil, -1, err } - if err = ioutils.AtomicWriteFile(r.tspath(id), templateTSdata, 0o600); err != nil { + if err := ioutils.AtomicWriteFile(r.tspath(id), templateTSdata, 0o600); err != nil { // We don't have a record of this layer, but at least // try to clean it up underneath us. if err2 := r.driver.Remove(id); err2 != nil { @@ -813,7 +812,7 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab return nil, -1, err } } - layer = &Layer{ + layer := &Layer{ ID: id, Parent: parent, Names: names, @@ -842,7 +841,7 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab layer.Flags[flag] = value } layer.Flags[incompleteFlag] = true - err = r.Save() + err := r.Save() if err != nil { // We don't have a presistent record of this layer, but // try to remove both the driver’s data as well as @@ -852,6 +851,7 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab } return nil, -1, err } + var size int64 = -1 if diff != nil { size, err = r.applyDiffWithOptions(layer.ID, moreOptions, diff) if err != nil { From c7ae082b7097bb061fb29d23c3a3ea40ba938375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Tue, 22 Feb 2022 01:11:26 +0100 Subject: [PATCH 5/6] Consolidate the error handling cleanup into a defer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... so that we don't repeat it all over the place. Introduce a pretty ugly cleanupFailureContext variable for that purpose; still, it's better than copy&pasting everything. This will be even more useful soon. Signed-off-by: Miloslav Trmač --- layers.go | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/layers.go b/layers.go index cea38a3c84..dd00c753c8 100644 --- a/layers.go +++ b/layers.go @@ -841,26 +841,32 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab layer.Flags[flag] = value } layer.Flags[incompleteFlag] = true + + succeeded := false + cleanupFailureContext := "" + defer func() { + if !succeeded { + // On any error, try both removing the driver's data as well + // as the in-memory layer record. + if err2 := r.Delete(layer.ID); err2 != nil { + if cleanupFailureContext == "" { + cleanupFailureContext = "unknown: cleanupFailureContext not set at the failure site" + } + logrus.Errorf("While recovering from a failure (%s), error deleting layer %#v: %v", cleanupFailureContext, layer.ID, err2) + } + } + }() + err := r.Save() if err != nil { - // We don't have a presistent record of this layer, but - // try to remove both the driver’s data as well as - // the in-memory layer record. - if err2 := r.Delete(layer.ID); err2 != nil { - logrus.Errorf("While recovering from a failure saving incomplete layer metadata, error deleting layer %#v: %v", id, err2) - } + cleanupFailureContext = "saving incomplete layer metadata" return nil, -1, err } var size int64 = -1 if diff != nil { size, err = r.applyDiffWithOptions(layer.ID, moreOptions, diff) if err != nil { - if err2 := r.Delete(layer.ID); err2 != nil { - // Either a driver error or an error saving. - // We now have a layer that's been marked for - // deletion but which we failed to remove. - logrus.Errorf("While recovering from a failure applying layer diff, error deleting layer %#v: %v", layer.ID, err2) - } + cleanupFailureContext = "applying layer diff" return nil, -1, err } } else { @@ -875,15 +881,12 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab delete(layer.Flags, incompleteFlag) err = r.Save() if err != nil { - if err2 := r.Delete(layer.ID); err2 != nil { - // Either a driver error or an error saving. - // We now have a layer that's been marked for - // deletion but which we failed to remove. - logrus.Errorf("While recovering from a failure saving finished layer metadata, error deleting layer %#v: %v", layer.ID, err2) - } + cleanupFailureContext = "saving finished layer metadata" return nil, -1, err } + layer = copyLayer(layer) + succeeded = true return layer, size, err } From 70cd76bfb0607ee4e34ea1fdf888607653455cb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Tue, 22 Feb 2022 01:17:28 +0100 Subject: [PATCH 6/6] Create a persistent record of an incomplete layer before creating it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... so that it can be also automatically cleaned up. Signed-off-by: Miloslav Trmač --- layers.go | 98 ++++++++++++++++++++++++++----------------------------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/layers.go b/layers.go index dd00c753c8..bba8d7588f 100644 --- a/layers.go +++ b/layers.go @@ -761,57 +761,9 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab if mountLabel != "" { label.ReserveLabel(mountLabel) } - idMappings := idtools.NewIDMappingsFromMaps(moreOptions.UIDMap, moreOptions.GIDMap) - opts := drivers.CreateOpts{ - MountLabel: mountLabel, - StorageOpt: options, - IDMappings: idMappings, - } - if moreOptions.TemplateLayer != "" { - if err := r.driver.CreateFromTemplate(id, moreOptions.TemplateLayer, templateIDMappings, parent, parentMappings, &opts, writeable); err != nil { - return nil, -1, errors.Wrapf(err, "error creating copy of template layer %q with ID %q", moreOptions.TemplateLayer, id) - } - oldMappings = templateIDMappings - } else { - if writeable { - if err := r.driver.CreateReadWrite(id, parent, &opts); err != nil { - return nil, -1, errors.Wrapf(err, "error creating read-write layer with ID %q", id) - } - } else { - if err := r.driver.Create(id, parent, &opts); err != nil { - return nil, -1, errors.Wrapf(err, "error creating layer with ID %q", id) - } - } - oldMappings = parentMappings - } - if !reflect.DeepEqual(oldMappings.UIDs(), idMappings.UIDs()) || !reflect.DeepEqual(oldMappings.GIDs(), idMappings.GIDs()) { - if err := r.driver.UpdateLayerIDMap(id, oldMappings, idMappings, mountLabel); err != nil { - // We don't have a record of this layer, but at least - // try to clean it up underneath us. - if err2 := r.driver.Remove(id); err2 != nil { - logrus.Errorf("While recovering from a failure creating in UpdateLayerIDMap, error deleting layer %#v: %v", id, err2) - } - return nil, -1, err - } - } - if len(templateTSdata) > 0 { - if err := os.MkdirAll(filepath.Dir(r.tspath(id)), 0o700); err != nil { - // We don't have a record of this layer, but at least - // try to clean it up underneath us. - if err2 := r.driver.Remove(id); err2 != nil { - logrus.Errorf("While recovering from a failure creating in UpdateLayerIDMap, error deleting layer %#v: %v", id, err2) - } - return nil, -1, err - } - if err := ioutils.AtomicWriteFile(r.tspath(id), templateTSdata, 0o600); err != nil { - // We don't have a record of this layer, but at least - // try to clean it up underneath us. - if err2 := r.driver.Remove(id); err2 != nil { - logrus.Errorf("While recovering from a failure creating in UpdateLayerIDMap, error deleting layer %#v: %v", id, err2) - } - return nil, -1, err - } - } + + // Before actually creating the layer, make a persistent record of it with incompleteFlag, + // so that future processes have a chance to delete it. layer := &Layer{ ID: id, Parent: parent, @@ -862,6 +814,50 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab cleanupFailureContext = "saving incomplete layer metadata" return nil, -1, err } + + idMappings := idtools.NewIDMappingsFromMaps(moreOptions.UIDMap, moreOptions.GIDMap) + opts := drivers.CreateOpts{ + MountLabel: mountLabel, + StorageOpt: options, + IDMappings: idMappings, + } + if moreOptions.TemplateLayer != "" { + if err := r.driver.CreateFromTemplate(id, moreOptions.TemplateLayer, templateIDMappings, parent, parentMappings, &opts, writeable); err != nil { + cleanupFailureContext = "creating a layer from template" + return nil, -1, errors.Wrapf(err, "error creating copy of template layer %q with ID %q", moreOptions.TemplateLayer, id) + } + oldMappings = templateIDMappings + } else { + if writeable { + if err := r.driver.CreateReadWrite(id, parent, &opts); err != nil { + cleanupFailureContext = "creating a read-write layer" + return nil, -1, errors.Wrapf(err, "error creating read-write layer with ID %q", id) + } + } else { + if err := r.driver.Create(id, parent, &opts); err != nil { + cleanupFailureContext = "creating a read-only layer" + return nil, -1, errors.Wrapf(err, "error creating layer with ID %q", id) + } + } + oldMappings = parentMappings + } + if !reflect.DeepEqual(oldMappings.UIDs(), idMappings.UIDs()) || !reflect.DeepEqual(oldMappings.GIDs(), idMappings.GIDs()) { + if err := r.driver.UpdateLayerIDMap(id, oldMappings, idMappings, mountLabel); err != nil { + cleanupFailureContext = "in UpdateLayerIDMap" + return nil, -1, err + } + } + if len(templateTSdata) > 0 { + if err := os.MkdirAll(filepath.Dir(r.tspath(id)), 0o700); err != nil { + cleanupFailureContext = "creating tar-split parent directory for a copy from template" + return nil, -1, err + } + if err := ioutils.AtomicWriteFile(r.tspath(id), templateTSdata, 0o600); err != nil { + cleanupFailureContext = "creating a tar-split copy from template" + return nil, -1, err + } + } + var size int64 = -1 if diff != nil { size, err = r.applyDiffWithOptions(layer.ID, moreOptions, diff)