Skip to content

Commit b7780f2

Browse files
committed
storage: when creating layer apply diff unlocked
Signed-off-by: Paul Holzinger <[email protected]>
1 parent e7313e6 commit b7780f2

File tree

1 file changed

+124
-15
lines changed

1 file changed

+124
-15
lines changed

storage/layers.go

Lines changed: 124 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,19 @@ func (r *layerStore) pickStoreLocation(volatile, writeable bool) layerLocations
13781378
}
13791379
}
13801380

1381+
func checkIdAndNameConflict(r *layerStore, id string, names []string) error {
1382+
if _, idInUse := r.byid[id]; idInUse {
1383+
return ErrDuplicateID
1384+
}
1385+
names = dedupeStrings(names)
1386+
for _, name := range names {
1387+
if _, nameInUse := r.byname[name]; nameInUse {
1388+
return ErrDuplicateName
1389+
}
1390+
}
1391+
return nil
1392+
}
1393+
13811394
// Requires startWriting.
13821395
func (r *layerStore) create(id string, parentLayer *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, diff io.Reader, slo *stagedLayerOptions) (layer *Layer, size int64, err error) {
13831396
if moreOptions == nil {
@@ -1400,14 +1413,9 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
14001413
_, idInUse = r.byid[id]
14011414
}
14021415
}
1403-
if duplicateLayer, idInUse := r.byid[id]; idInUse {
1404-
return duplicateLayer, -1, ErrDuplicateID
1405-
}
14061416
names = dedupeStrings(names)
1407-
for _, name := range names {
1408-
if _, nameInUse := r.byname[name]; nameInUse {
1409-
return nil, -1, ErrDuplicateName
1410-
}
1417+
if err := checkIdAndNameConflict(r, id, names); err != nil {
1418+
return nil, -1, err
14111419
}
14121420
parent := ""
14131421
if parentLayer != nil {
@@ -1448,9 +1456,6 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
14481456
selinux.ReserveLabel(mountLabel)
14491457
}
14501458

1451-
// Before actually creating the layer, make a persistent record of it
1452-
// with the incomplete flag set, so that future processes have a chance
1453-
// to clean up after it.
14541459
layer = &Layer{
14551460
ID: id,
14561461
Parent: parent,
@@ -1474,6 +1479,41 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
14741479
}
14751480
layer.Flags[incompleteFlag] = true
14761481

1482+
var (
1483+
cleanupFunctions []tempdir.CleanupTempDirFunc
1484+
applyDiffFunc func() error
1485+
applyDiffSize int64
1486+
)
1487+
1488+
applyDiffTemporaryDriver, ok := r.driver.(drivers.ApplyDiffStaging)
1489+
if ok && diff != nil {
1490+
// CRITICAL, this releases the lock so we can extract this unlocked
1491+
r.stopWriting()
1492+
1493+
var applyDiffError error
1494+
cleanupFunctions, applyDiffFunc, applyDiffSize, applyDiffError = r.applyDiffUnlocked(applyDiffTemporaryDriver, layer, moreOptions, diff)
1495+
// We must try to cleanup reagrdless of if an error was returned or not.
1496+
defer tempdir.CleanupTemporaryDirectories(cleanupFunctions...)
1497+
// Acquire the lock again, this releases the lock so we can extract this unlocked.
1498+
// This must be done before checking for the error from applyDiffUnlocked() so the caller doesn't try to unlock again.
1499+
// FIXME: if startWriting() fails we return unlocked and then the parent unlocks again causing a panic. We should try to avoid that case somehow.
1500+
if err := r.startWriting(); err != nil {
1501+
return nil, -1, fmt.Errorf("re-acquire lock after applying layer diff: %w", err)
1502+
}
1503+
if applyDiffError != nil {
1504+
return nil, -1, applyDiffError
1505+
}
1506+
1507+
if err := checkIdAndNameConflict(r, id, names); err != nil {
1508+
logrus.Debugf("Layer id %s or name from %v was created while staging the layer content unlocked, aborting layer creation", id, names)
1509+
return nil, -1, err
1510+
}
1511+
}
1512+
1513+
// Before actually creating the layer, make a persistent record of it
1514+
// with the incomplete flag set, so that future processes have a chance
1515+
// to clean up after it.
1516+
14771517
r.layers = append(r.layers, layer)
14781518
// This can only fail if the ID is already missing, which shouldn’t
14791519
// happen — and in that case the index is already in the desired state
@@ -1568,7 +1608,13 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
15681608
}
15691609

15701610
size = -1
1571-
if diff != nil {
1611+
if applyDiffFunc != nil {
1612+
size = applyDiffSize
1613+
if err := applyDiffFunc(); err != nil {
1614+
cleanupFailureContext = "applying staged diff"
1615+
return nil, -1, err
1616+
}
1617+
} else if diff != nil {
15721618
if size, err = r.applyDiffWithOptions(layer, moreOptions, diff); err != nil {
15731619
cleanupFailureContext = "applying layer diff"
15741620
return nil, -1, err
@@ -2404,6 +2450,66 @@ func (r *layerStore) ApplyDiff(to string, diff io.Reader) (size int64, err error
24042450

24052451
type diffApplyFunc func(id string, parent string, options drivers.ApplyDiffOpts, tsBytes *bytes.Buffer) error
24062452

2453+
func (r *layerStore) applyDiffUnlocked(dd drivers.ApplyDiffStaging, layer *Layer, layerOptions *LayerOptions, diff io.Reader) ([]tempdir.CleanupTempDirFunc, func() error, int64, error) {
2454+
var (
2455+
size int64
2456+
cleanFunctions []tempdir.CleanupTempDirFunc
2457+
applyDiff func() error
2458+
)
2459+
2460+
f := func(id string, parent string, options drivers.ApplyDiffOpts, tsBytes *bytes.Buffer) error {
2461+
var (
2462+
err error
2463+
cleanup tempdir.CleanupTempDirFunc
2464+
commit tempdir.CommitFunc
2465+
)
2466+
cleanup, commit, size, err = dd.StartStagingDiffToApply(layer.ID, layer.Parent, options)
2467+
cleanFunctions = append(cleanFunctions, cleanup)
2468+
if err != nil {
2469+
return err
2470+
}
2471+
2472+
td, err := tempdir.NewTempDir(filepath.Join(r.layerdir, tempDirPath))
2473+
cleanFunctions = append(cleanFunctions, td.Cleanup)
2474+
if err != nil {
2475+
return err
2476+
}
2477+
2478+
sa, err := td.StageFileAddition(func(path string) error {
2479+
return os.WriteFile(path, tsBytes.Bytes(), 0o600)
2480+
})
2481+
cleanFunctions = append(cleanFunctions, td.Cleanup)
2482+
if err != nil {
2483+
return err
2484+
}
2485+
2486+
applyDiff = func() error {
2487+
err := dd.CommitStagedLayer(layer.ID, commit)
2488+
if err != nil {
2489+
return fmt.Errorf("commit temporary layer: %w", err)
2490+
}
2491+
2492+
if err := os.MkdirAll(filepath.Dir(r.tspath(layer.ID)), 0o700); err != nil {
2493+
return err
2494+
}
2495+
2496+
err = sa.Commit(r.tspath(layer.ID))
2497+
if err != nil {
2498+
return fmt.Errorf("commit tar split file: %w", err)
2499+
}
2500+
return nil
2501+
}
2502+
return nil
2503+
}
2504+
2505+
err := r.applyDiffWithOptionsInner(layer, layerOptions, diff, f)
2506+
if err != nil {
2507+
return cleanFunctions, nil, 0, err
2508+
}
2509+
2510+
return cleanFunctions, applyDiff, size, nil
2511+
}
2512+
24072513
// Requires startWriting.
24082514
func (r *layerStore) applyDiffWithOptions(layer *Layer, layerOptions *LayerOptions, diff io.Reader) (int64, error) {
24092515
var size int64
@@ -2422,7 +2528,12 @@ func (r *layerStore) applyDiffWithOptions(layer *Layer, layerOptions *LayerOptio
24222528
return nil
24232529
}
24242530

2425-
return size, r.applyDiffWithOptionsInner(layer, layerOptions, diff, f)
2531+
err := r.applyDiffWithOptionsInner(layer, layerOptions, diff, f)
2532+
if err != nil {
2533+
return 0, err
2534+
}
2535+
2536+
return size, r.saveFor(layer)
24262537
}
24272538

24282539
func (r *layerStore) applyDiffWithOptionsInner(layer *Layer, layerOptions *LayerOptions, diff io.Reader, applyFunc diffApplyFunc) (err error) {
@@ -2545,9 +2656,7 @@ func (r *layerStore) applyDiffWithOptionsInner(layer *Layer, layerOptions *Layer
25452656
}
25462657
slices.Sort(layer.GIDs)
25472658

2548-
err = r.saveFor(layer)
2549-
2550-
return err
2659+
return nil
25512660
}
25522661

25532662
// Requires (startReading or?) startWriting.

0 commit comments

Comments
 (0)