Skip to content

Commit 91fcdbb

Browse files
committed
storage: do conflict checks before staging untar
The untar can be quite expensive so check for id, name conflicts right away. Also we must populate the idmappings so we extract with the right uids/gids. Signed-off-by: Paul Holzinger <[email protected]>
1 parent d281fa9 commit 91fcdbb

File tree

2 files changed

+80
-27
lines changed

2 files changed

+80
-27
lines changed

storage/layers.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,11 @@ type rwLayerStore interface {
326326
// diff which was applied to its parent to initialize its contents.
327327
create(id string, parent *Layer, names []string, mountLabel string, options map[string]string, moreOptions *LayerOptions, writeable bool, slo *stagedLayerOptions) (*Layer, int64, error)
328328

329+
// checkIdOrNameConfict checks if the id or names are already in use and returns an
330+
// error in that case. As Special case if the layer already exists it returns it as
331+
// well together with the error.
332+
checkIdOrNameConfict(id string, names []string) (*Layer, error)
333+
329334
// updateNames modifies names associated with a layer based on (op, names).
330335
updateNames(id string, names []string, op updateNameOperation) error
331336

storage/store.go

Lines changed: 75 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,6 +1456,30 @@ func (s *store) putLayer(rlstore rwLayerStore, id string, parentLayer *Layer, na
14561456
return rlstore.create(id, parentLayer, names, mountLabel, nil, options, writeable, slo)
14571457
}
14581458

1459+
// On entry:
1460+
// - rlstore must be locked for writing
1461+
// - rlstores MUST NOT be locked
1462+
func getParentLayer(rlstore rwLayerStore, rlstores []roLayerStore, parent string) (*Layer, error) {
1463+
var ilayer *Layer
1464+
for _, l := range append([]roLayerStore{rlstore}, rlstores...) {
1465+
lstore := l
1466+
if lstore != rlstore {
1467+
if err := lstore.startReading(); err != nil {
1468+
return nil, err
1469+
}
1470+
defer lstore.stopReading()
1471+
}
1472+
if l, err := lstore.Get(parent); err == nil && l != nil {
1473+
ilayer = l
1474+
break
1475+
}
1476+
}
1477+
if ilayer == nil {
1478+
return nil, ErrLayerUnknown
1479+
}
1480+
return ilayer, nil
1481+
}
1482+
14591483
// On entry:
14601484
// - rlstore must be locked for writing
14611485
// - rlstores MUST NOT be locked
@@ -1478,25 +1502,11 @@ func populateLayerOptions(s *store, rlstore rwLayerStore, rlstores []roLayerStor
14781502
uidMap := options.UIDMap
14791503
gidMap := options.GIDMap
14801504
if parent != "" {
1481-
var ilayer *Layer
1482-
for _, l := range append([]roLayerStore{rlstore}, rlstores...) {
1483-
lstore := l
1484-
if lstore != rlstore {
1485-
if err := lstore.startReading(); err != nil {
1486-
return nil, nil, err
1487-
}
1488-
defer lstore.stopReading()
1489-
}
1490-
if l, err := lstore.Get(parent); err == nil && l != nil {
1491-
ilayer = l
1492-
parent = ilayer.ID
1493-
break
1494-
}
1495-
}
1496-
if ilayer == nil {
1497-
return nil, nil, ErrLayerUnknown
1505+
var err error
1506+
parentLayer, err = getParentLayer(rlstore, rlstores, parent)
1507+
if err != nil {
1508+
return nil, nil, err
14981509
}
1499-
parentLayer = ilayer
15001510

15011511
if err := s.containerStore.startWriting(); err != nil {
15021512
return nil, nil, err
@@ -1512,10 +1522,10 @@ func populateLayerOptions(s *store, rlstore rwLayerStore, rlstores []roLayerStor
15121522
}
15131523
}
15141524
if !options.HostUIDMapping && len(options.UIDMap) == 0 {
1515-
uidMap = ilayer.UIDMap
1525+
uidMap = parentLayer.UIDMap
15161526
}
15171527
if !options.HostGIDMapping && len(options.GIDMap) == 0 {
1518-
gidMap = ilayer.GIDMap
1528+
gidMap = parentLayer.GIDMap
15191529
}
15201530
} else {
15211531
if !options.HostUIDMapping && len(options.UIDMap) == 0 {
@@ -1544,7 +1554,11 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
15441554
return nil, -1, err
15451555
}
15461556

1547-
var slo *stagedLayerOptions
1557+
var (
1558+
slo *stagedLayerOptions
1559+
options *LayerOptions
1560+
parentLayer *Layer
1561+
)
15481562

15491563
if diff != nil {
15501564
m := rlstore.newMaybeStagedLayerExtraction(diff)
@@ -1553,10 +1567,32 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
15531567
logrus.Errorf("Error cleaning up temporary directories: %v", err)
15541568
}
15551569
}()
1556-
err = rlstore.stageWithUnlockedStore(m, lOptions)
1557-
if err != nil {
1558-
return nil, -1, err
1570+
// driver can do unlocked staging so do that without holding the layer lock
1571+
if m.staging != nil {
1572+
// func so we have a scope for defer, we don't want to hold the lock for stageWithUnlockedStore()
1573+
layer, err := func() (*Layer, error) {
1574+
if err := rlstore.startWriting(); err != nil {
1575+
return nil, err
1576+
}
1577+
defer rlstore.stopWriting()
1578+
1579+
if layer, err := rlstore.checkIdOrNameConfict(id, names); err != nil {
1580+
return layer, err
1581+
}
1582+
1583+
options, parentLayer, err = populateLayerOptions(s, rlstore, rlstores, parent, lOptions)
1584+
return nil, err
1585+
}()
1586+
if err != nil {
1587+
return layer, -1, err
1588+
}
1589+
1590+
err = rlstore.stageWithUnlockedStore(m, options)
1591+
if err != nil {
1592+
return nil, -1, err
1593+
}
15591594
}
1595+
15601596
slo = &stagedLayerOptions{
15611597
stagedLayerExtraction: m,
15621598
}
@@ -1567,9 +1603,21 @@ func (s *store) PutLayer(id, parent string, names []string, mountLabel string, w
15671603
}
15681604
defer rlstore.stopWriting()
15691605

1570-
options, parentLayer, err := populateLayerOptions(s, rlstore, rlstores, parent, lOptions)
1571-
if err != nil {
1572-
return nil, -1, err
1606+
if parentLayer == nil {
1607+
// options where not populated yet
1608+
options, parentLayer, err = populateLayerOptions(s, rlstore, rlstores, parent, lOptions)
1609+
if err != nil {
1610+
return nil, -1, err
1611+
}
1612+
} else {
1613+
// We used the staged extraction without holding the lock.
1614+
// Check again that the parent layer is still valid and exists.
1615+
_, err := getParentLayer(rlstore, rlstores, parentLayer.ID)
1616+
if err != nil {
1617+
return nil, -1, err
1618+
}
1619+
// FIXME: I guess we should compare the old parentLayer uid/gid mappings with the newly looked up layer here?
1620+
// Could it happen that a layer with the same id was deleted on recreated with new mapping while we where unlocked?
15731621
}
15741622
return s.putLayer(rlstore, id, parentLayer, names, mountLabel, writeable, options, slo)
15751623
}

0 commit comments

Comments
 (0)