Skip to content

Commit 081c251

Browse files
authored
Merge pull request #783 from mtrmac/overlay
Overlay cleanups after #666
2 parents 26e96a3 + e4ee402 commit 081c251

1 file changed

Lines changed: 120 additions & 151 deletions

File tree

storage/drivers/overlay/overlay.go

Lines changed: 120 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,7 @@ import (
4848
var untar = chrootarchive.UntarUncompressed
4949

5050
const (
51-
defaultPerms = os.FileMode(0o555)
52-
mountProgramFlagFile = ".has-mount-program"
51+
defaultPerms = os.FileMode(0o555)
5352
)
5453

5554
// This backend uses the overlay union filesystem for containers
@@ -79,24 +78,32 @@ const (
7978
// syscall. A hard upper limit of 500 lower layers is enforced to ensure
8079
// that mounts do not fail due to length.
8180

82-
const (
83-
linkDir = "l"
84-
stagingDir = "staging"
85-
tempDirName = "tempdirs"
86-
lowerFile = "lower"
81+
const ( // Paths within the driver’s home directory
82+
mountProgramFlagFile = ".has-mount-program"
83+
linkDir = "l"
84+
stagingDir = "staging"
85+
tempDirName = "tempdirs"
86+
)
87+
88+
const ( // Paths within a per-layer directory
89+
lowerFile = "lower"
8790
// lowerLayersFile references lower layers directly by layer ID
8891
// instead of going through the l/ symlinks. The code appends
8992
// "/diff" itself when consuming entries. It is preferred over
9093
// lowerFile when present. The old lowerFile is still written
9194
// for backward compatibility with older tools.
9295
lowerLayersFile = "lower-layers"
93-
maxDepth = 500
94-
95-
stagingLockFile = "staging.lock"
96+
)
9697

98+
const ( // Keys within DriverWithDifferOutput.Artifacts
9799
tocArtifact = "toc"
98100
fsVerityDigestsArtifact = "fs-verity-digests"
101+
)
102+
103+
const stagingLockFile = "staging.lock"
99104

105+
const (
106+
maxDepth = 500
100107
// idLength represents the number of random characters
101108
// which can be used to create the unique link identifier
102109
// for every layer. If this value is too long then the
@@ -1145,42 +1152,22 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl
11451152
return idtools.MkdirAndChown(path.Join(dir, "empty"), 0o700, forcedSt.IDs)
11461153
}
11471154

1148-
lower, err := d.getLower(parent)
1155+
lower, err := d.getLowerForParent(parent)
11491156
if err != nil {
11501157
return err
11511158
}
1152-
if lower != "" {
1153-
if err := os.WriteFile(path.Join(dir, lowerFile), []byte(lower), 0o666); err != nil {
1154-
return err
1155-
}
1159+
if err := os.WriteFile(path.Join(dir, lowerFile), []byte(lower), 0o666); err != nil {
1160+
return err
11561161
}
11571162

11581163
// Write a lower-layers file referencing layers by ID instead of
11591164
// l/ symlink references. The reading side appends "/diff" itself.
1160-
parentDir := d.dir(parent)
1161-
layerLower := parent
1162-
parentLower, err := os.ReadFile(path.Join(parentDir, lowerLayersFile))
1163-
if err == nil {
1164-
layerLower += ":" + string(parentLower)
1165-
} else if !errors.Is(err, unix.ENOENT) {
1165+
parentLowerLayerIDs, err := d.getLowerLayerIDs(parent)
1166+
if err != nil {
11661167
return err
1167-
} else {
1168-
// Parent has no lower-layers file. Convert old-format lower
1169-
// entries (l/ symlinks) to layer IDs.
1170-
oldLower, err := os.ReadFile(path.Join(parentDir, lowerFile))
1171-
if err == nil {
1172-
for _, s := range strings.Split(string(oldLower), ":") {
1173-
target, err := os.Readlink(d.dir(s))
1174-
if err != nil {
1175-
return fmt.Errorf("reading symlink for lower %q: %w", s, err)
1176-
}
1177-
layerLower += ":" + filepath.Base(filepath.Dir(target))
1178-
}
1179-
} else if !errors.Is(err, unix.ENOENT) {
1180-
return err
1181-
}
11821168
}
1183-
if err := os.WriteFile(path.Join(dir, lowerLayersFile), []byte(layerLower), 0o666); err != nil {
1169+
layerLowerLayerIDs := strings.Join(append([]string{parent}, parentLowerLayerIDs...), ":")
1170+
if err := os.WriteFile(path.Join(dir, lowerLayersFile), []byte(layerLowerLayerIDs), 0o666); err != nil {
11841171
return err
11851172
}
11861173

@@ -1231,28 +1218,6 @@ func (d *Driver) parseStorageOpt(opts *graphdriver.CreateOpts, readOnly bool) (q
12311218
return res, nil
12321219
}
12331220

1234-
func (d *Driver) getLower(parent string) (string, error) {
1235-
parentDir := d.dir(parent)
1236-
1237-
// Ensure parent exists
1238-
if err := fileutils.Lexists(parentDir); err != nil {
1239-
return "", err
1240-
}
1241-
1242-
parentLink, err := os.ReadFile(path.Join(parentDir, "link"))
1243-
if err != nil {
1244-
return "", err
1245-
}
1246-
lowers := []string{path.Join(linkDir, string(parentLink))}
1247-
1248-
parentLower, err := os.ReadFile(path.Join(parentDir, lowerFile))
1249-
if err == nil {
1250-
parentLowers := strings.SplitSeq(string(parentLower), ":")
1251-
lowers = slices.AppendSeq(lowers, parentLowers)
1252-
}
1253-
return strings.Join(lowers, ":"), nil
1254-
}
1255-
12561221
func (d *Driver) dir(id string) string {
12571222
p, _, _ := d.dir2(id, false)
12581223
return p
@@ -1294,36 +1259,98 @@ func (d *Driver) dir2(id string, useImageStore bool) (string, string, bool) {
12941259
return newpath, homedir, false
12951260
}
12961261

1297-
func (d *Driver) getLowerDirs(id string) ([]string, error) {
1298-
var lowersArray []string
1299-
dir := d.dir(id)
1300-
lowers, err := os.ReadFile(path.Join(dir, lowerLayersFile))
1262+
// getLowerForParent returns the contents of lowerFile for a child layer of parent.
1263+
//
1264+
// This should only be used to construct a lowerFile for compatibility;
1265+
// new code should rely on lowerLayersFile instead.
1266+
func (d *Driver) getLowerForParent(parent string) (string, error) {
1267+
parentDir := d.dir(parent)
1268+
1269+
// Ensure parent exists
1270+
if err := fileutils.Lexists(parentDir); err != nil {
1271+
return "", err
1272+
}
1273+
1274+
parentLink, err := os.ReadFile(path.Join(parentDir, "link"))
13011275
if err != nil {
1302-
if !errors.Is(err, unix.ENOENT) {
1303-
return nil, err
1304-
}
1305-
lowers, err = os.ReadFile(path.Join(dir, lowerFile))
1276+
return "", err
13061277
}
1278+
lowers := []string{path.Join(linkDir, string(parentLink))}
1279+
1280+
parentLower, err := os.ReadFile(path.Join(parentDir, lowerFile))
13071281
if err == nil {
1308-
for s := range strings.SplitSeq(string(lowers), ":") {
1309-
lower := d.dir(s)
1310-
lp, err := os.Readlink(lower)
1282+
parentLowers := strings.SplitSeq(string(parentLower), ":")
1283+
lowers = slices.AppendSeq(lowers, parentLowers)
1284+
}
1285+
return strings.Join(lowers, ":"), nil
1286+
}
1287+
1288+
// getLowerLayerIDs returns a list of lower layer IDs for a layer id;
1289+
// typically the contents of lowerLayersFile, falling back to lowerFile.
1290+
// If the layer has neither of the files, returns an empty list without reporting an error.
1291+
func (d *Driver) getLowerLayerIDs(id string) ([]string, error) {
1292+
dir := d.dir(id)
1293+
lowerLayers, err := os.ReadFile(path.Join(dir, lowerLayersFile))
1294+
switch {
1295+
case err == nil:
1296+
return strings.Split(string(lowerLayers), ":"), nil
1297+
1298+
case errors.Is(err, fs.ErrNotExist):
1299+
lowers, err := os.ReadFile(path.Join(dir, lowerFile))
1300+
if err != nil {
1301+
if errors.Is(err, fs.ErrNotExist) {
1302+
return nil, nil
1303+
}
1304+
return nil, err
1305+
}
1306+
var res []string
1307+
for relLowerLink := range strings.SplitSeq(string(lowers), ":") {
1308+
lowerLink := d.dir(relLowerLink) // This is an invalid use of dir() (the input is supposed to be a layer ID) but pre-existing
1309+
lp, err := os.Readlink(lowerLink)
13111310
if err != nil {
1312-
if errors.Is(err, syscall.EINVAL) {
1313-
// Not a symlink: layer ID, append /diff.
1314-
lowersArray = append(lowersArray, path.Join(lower, "diff"))
1315-
continue
1316-
}
13171311
return nil, err
13181312
}
1319-
lowersArray = append(lowersArray, path.Clean(d.dir(path.Join("link", lp))))
1313+
lowerID := filepath.Base(filepath.Dir(lp))
1314+
res = append(res, lowerID)
13201315
}
1321-
} else if !errors.Is(err, fs.ErrNotExist) {
1316+
return res, nil
1317+
1318+
default:
13221319
return nil, err
13231320
}
1321+
}
1322+
1323+
// getLowerDirs returns a list of lower directories for a layer id;
1324+
// the directories may be symbolic links (do not call redirectDiffIfAdditionalLayer).
1325+
func (d *Driver) getLowerDirs(id string) ([]string, error) {
1326+
lowerLayerIDs, err := d.getLowerLayerIDs(id)
1327+
if err != nil {
1328+
return nil, err
1329+
}
1330+
lowersArray := make([]string, 0, len(lowerLayerIDs))
1331+
for _, lowerID := range lowerLayerIDs {
1332+
lowerDir := d.dir(lowerID)
1333+
lowersArray = append(lowersArray, path.Join(lowerDir, "diff"))
1334+
}
13241335
return lowersArray, nil
13251336
}
13261337

1338+
// getLowerDiffPaths returns a list of lower diff paths for a layer id;
1339+
// the paths have redirectDiffIfAdditionalLayer applied.
1340+
func (d *Driver) getLowerDiffPaths(id string) ([]string, error) {
1341+
layers, err := d.getLowerDirs(id)
1342+
if err != nil {
1343+
return nil, err
1344+
}
1345+
for i, l := range layers {
1346+
layers[i], err = redirectDiffIfAdditionalLayer(l, false)
1347+
if err != nil {
1348+
return nil, err
1349+
}
1350+
}
1351+
return layers, nil
1352+
}
1353+
13271354
func (d *Driver) optsAppendMappings(opts string, uidMaps, gidMaps []idtools.IDMap) string {
13281355
if uidMaps != nil {
13291356
var uids, gids bytes.Buffer
@@ -1520,18 +1547,11 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
15201547
readWrite = false
15211548
}
15221549

1523-
lowers, err := os.ReadFile(path.Join(dir, lowerLayersFile))
1550+
lowerLayerIDs, err := d.getLowerLayerIDs(id)
15241551
if err != nil {
1525-
if !errors.Is(err, unix.ENOENT) {
1526-
return "", err
1527-
}
1528-
lowers, err = os.ReadFile(path.Join(dir, lowerFile))
1529-
if err != nil && !os.IsNotExist(err) {
1530-
return "", err
1531-
}
1552+
return "", err
15321553
}
1533-
splitLowers := strings.Split(string(lowers), ":")
1534-
if len(splitLowers) > maxDepth {
1554+
if len(lowerLayerIDs) > maxDepth {
15351555
return "", errors.New("max depth exceeded")
15361556
}
15371557

@@ -1621,46 +1641,17 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
16211641

16221642
// For each lower, resolve its path, and append it and any additional diffN
16231643
// directories to the lowers list.
1624-
for i, l := range splitLowers {
1625-
if l == "" {
1626-
continue
1644+
for i, lowerID := range lowerLayerIDs {
1645+
lower := filepath.Join(d.dir(lowerID), "diff")
1646+
st, err := os.Stat(lower)
1647+
if err != nil {
1648+
return "", fmt.Errorf("can't stat (or find?) lower layer %q: %w", lower, err)
16271649
}
1628-
1629-
lower := ""
1630-
newpath := path.Join(d.home, l)
1631-
if st, err := os.Stat(newpath); err != nil {
1632-
for _, p := range d.getAllImageStores() {
1633-
lower = path.Join(p, d.name, l)
1634-
if st2, err2 := os.Stat(lower); err2 == nil {
1635-
if !permsKnown {
1636-
perms = st2.Mode()
1637-
permsKnown = true
1638-
}
1639-
break
1640-
}
1641-
lower = ""
1642-
}
1643-
if lower == "" {
1644-
return "", fmt.Errorf("can't stat lower layer %q: %w", newpath, err)
1645-
}
1646-
} else {
1647-
if !permsKnown {
1648-
perms = st.Mode()
1649-
permsKnown = true
1650-
}
1651-
lower = newpath
1650+
if !permsKnown {
1651+
perms = st.Mode()
1652+
permsKnown = true
16521653
}
16531654

1654-
linkContent, err := os.Readlink(lower)
1655-
if err != nil {
1656-
if !errors.Is(err, syscall.EINVAL) {
1657-
return "", err
1658-
}
1659-
// Not a symlink: layer ID from lower-layers, append /diff.
1660-
lower = path.Join(lower, "diff")
1661-
linkContent = lower
1662-
}
1663-
lowerID := filepath.Base(filepath.Dir(linkContent))
16641655
composefsMount, err := maybeAddComposefsMount(lowerID, i+1, readWrite)
16651656
if err != nil {
16661657
return "", err
@@ -2030,23 +2021,15 @@ func (d *Driver) ListLayers() ([]string, error) {
20302021

20312022
// isParent returns if the passed in parent is the direct parent of the passed in layer
20322023
func (d *Driver) isParent(id, parent string) bool {
2033-
lowers, err := d.getLowerDirs(id)
2024+
lowerLayerIDs, err := d.getLowerLayerIDs(id)
20342025
if err != nil {
20352026
return false
20362027
}
2037-
if parent == "" && len(lowers) > 0 {
2038-
return false
2039-
}
2040-
2041-
parentDir := d.dir(parent)
2042-
var ld string
2043-
if len(lowers) > 0 {
2044-
ld = filepath.Dir(lowers[0])
2045-
}
2046-
if ld == "" && parent == "" {
2047-
return true
2028+
actualParent := ""
2029+
if len(lowerLayerIDs) > 0 {
2030+
actualParent = lowerLayerIDs[0]
20482031
}
2049-
return ld == parentDir
2032+
return parent == actualParent
20502033
}
20512034

20522035
func (d *Driver) getWhiteoutFormat() archive.WhiteoutFormat {
@@ -2430,20 +2413,6 @@ func (d *Driver) getDiffPath(id string) (string, error) {
24302413
return redirectDiffIfAdditionalLayer(path.Join(dir, "diff"), false)
24312414
}
24322415

2433-
func (d *Driver) getLowerDiffPaths(id string) ([]string, error) {
2434-
layers, err := d.getLowerDirs(id)
2435-
if err != nil {
2436-
return nil, err
2437-
}
2438-
for i, l := range layers {
2439-
layers[i], err = redirectDiffIfAdditionalLayer(l, false)
2440-
if err != nil {
2441-
return nil, err
2442-
}
2443-
}
2444-
return layers, nil
2445-
}
2446-
24472416
// DiffSize calculates the changes between the specified id
24482417
// and its parent and returns the size in bytes of the changes
24492418
// relative to its base filesystem directory.

0 commit comments

Comments
 (0)