@@ -84,7 +84,13 @@ const (
8484 stagingDir = "staging"
8585 tempDirName = "tempdirs"
8686 lowerFile = "lower"
87- maxDepth = 500
87+ // lowerLayersFile references lower layers directly by layer ID
88+ // instead of going through the l/ symlinks. The code appends
89+ // "/diff" itself when consuming entries. It is preferred over
90+ // lowerFile when present. The old lowerFile is still written
91+ // for backward compatibility with older tools.
92+ lowerLayersFile = "lower-layers"
93+ maxDepth = 500
8894
8995 stagingLockFile = "staging.lock"
9096
@@ -327,7 +333,16 @@ func Init(home string, options graphdriver.Options) (graphdriver.Driver, error)
327333
328334 runhome := filepath .Join (options .RunRoot , filepath .Base (home ))
329335
330- // Create the driver home dir
336+ // Create the driver home dir.
337+ // NOTE: the l/ subdirectory currently also serves as an anchor that
338+ // prevents the home directory from being removed when all layers are
339+ // deleted. If l/ is dropped entirely in the future, an alternative
340+ // mechanism (e.g. a sentinel file) must be put in place to keep the
341+ // home directory around. Without it, supportsOverlay() on the error
342+ // path and checkAndRecordOverlaySupport() would successfully rmdir
343+ // the home, breaking XFS project quotas set on the directory and
344+ // causing ScanPriorDrivers() to no longer detect the overlay driver
345+ // as in use.
331346 if err := os .MkdirAll (path .Join (home , linkDir ), 0o755 ); err != nil {
332347 return nil , err
333348 }
@@ -1178,6 +1193,35 @@ func (d *Driver) create(id, parent string, opts *graphdriver.CreateOpts, readOnl
11781193 }
11791194 }
11801195
1196+ // Write a lower-layers file referencing layers by ID instead of
1197+ // l/ symlink references. The reading side appends "/diff" itself.
1198+ parentDir := d .dir (parent )
1199+ layerLower := parent
1200+ parentLower , err := os .ReadFile (path .Join (parentDir , lowerLayersFile ))
1201+ if err == nil {
1202+ layerLower += ":" + string (parentLower )
1203+ } else if ! errors .Is (err , unix .ENOENT ) {
1204+ return err
1205+ } else {
1206+ // Parent has no lower-layers file. Convert old-format lower
1207+ // entries (l/ symlinks) to layer IDs.
1208+ oldLower , err := os .ReadFile (path .Join (parentDir , lowerFile ))
1209+ if err == nil {
1210+ for _ , s := range strings .Split (string (oldLower ), ":" ) {
1211+ target , err := os .Readlink (d .dir (s ))
1212+ if err != nil {
1213+ return fmt .Errorf ("reading symlink for lower %q: %w" , s , err )
1214+ }
1215+ layerLower += ":" + filepath .Base (filepath .Dir (target ))
1216+ }
1217+ } else if ! errors .Is (err , unix .ENOENT ) {
1218+ return err
1219+ }
1220+ }
1221+ if err := os .WriteFile (path .Join (dir , lowerLayersFile ), []byte (layerLower ), 0o666 ); err != nil {
1222+ return err
1223+ }
1224+
11811225 return nil
11821226}
11831227
@@ -1215,20 +1259,9 @@ func (d *Driver) getLower(parent string) (string, error) {
12151259 return "" , err
12161260 }
12171261
1218- // Read Parent link fileA
12191262 parentLink , err := os .ReadFile (path .Join (parentDir , "link" ))
12201263 if err != nil {
1221- if ! errors .Is (err , fs .ErrNotExist ) {
1222- return "" , err
1223- }
1224- logrus .Warnf ("Can't read parent link %q because it does not exist. Going through storage to recreate the missing links." , path .Join (parentDir , "link" ))
1225- if err := d .recreateSymlinks (); err != nil {
1226- return "" , fmt .Errorf ("recreating the links: %w" , err )
1227- }
1228- parentLink , err = os .ReadFile (path .Join (parentDir , "link" ))
1229- if err != nil {
1230- return "" , err
1231- }
1264+ return "" , err
12321265 }
12331266 lowers := []string {path .Join (linkDir , string (parentLink ))}
12341267
@@ -1283,27 +1316,25 @@ func (d *Driver) dir2(id string, useImageStore bool) (string, string, bool) {
12831316
12841317func (d * Driver ) getLowerDirs (id string ) ([]string , error ) {
12851318 var lowersArray []string
1286- lowers , err := os .ReadFile (path .Join (d .dir (id ), lowerFile ))
1319+ dir := d .dir (id )
1320+ lowers , err := os .ReadFile (path .Join (dir , lowerLayersFile ))
1321+ if err != nil {
1322+ if ! errors .Is (err , unix .ENOENT ) {
1323+ return nil , err
1324+ }
1325+ lowers , err = os .ReadFile (path .Join (dir , lowerFile ))
1326+ }
12871327 if err == nil {
12881328 for s := range strings .SplitSeq (string (lowers ), ":" ) {
12891329 lower := d .dir (s )
12901330 lp , err := os .Readlink (lower )
1291- // if the link does not exist, we lost the symlinks during a sudden reboot.
1292- // Let's go ahead and recreate those symlinks.
12931331 if err != nil {
1294- if errors .Is (err , fs .ErrNotExist ) {
1295- logrus .Warnf ("Can't read link %q because it does not exist. A storage corruption might have occurred, attempting to recreate the missing symlinks. It might be best wipe the storage to avoid further errors due to storage corruption." , lower )
1296- if err := d .recreateSymlinks (); err != nil {
1297- return nil , fmt .Errorf ("recreating the missing symlinks: %w" , err )
1298- }
1299- // let's call Readlink on lower again now that we have recreated the missing symlinks
1300- lp , err = os .Readlink (lower )
1301- if err != nil {
1302- return nil , err
1303- }
1304- } else {
1305- return nil , err
1332+ if errors .Is (err , syscall .EINVAL ) {
1333+ // Not a symlink: layer ID, append /diff.
1334+ lowersArray = append (lowersArray , path .Join (lower , "diff" ))
1335+ continue
13061336 }
1337+ return nil , err
13071338 }
13081339 lowersArray = append (lowersArray , path .Clean (d .dir (path .Join ("link" , lp ))))
13091340 }
@@ -1415,112 +1446,6 @@ func (d *Driver) DeferredRemove(id string) (tempdir.CleanupTempDirFunc, error) {
14151446 return t .Cleanup , nil
14161447}
14171448
1418- // recreateSymlinks goes through the driver's home directory and checks if the diff directory
1419- // under each layer has a symlink created for it under the linkDir. If the symlink does not
1420- // exist, it creates them
1421- func (d * Driver ) recreateSymlinks () error {
1422- // We have at most 3 corrective actions per layer, so 10 iterations is plenty.
1423- const maxIterations = 10
1424-
1425- // List all the directories under the home directory
1426- dirs , err := os .ReadDir (d .home )
1427- if err != nil {
1428- return fmt .Errorf ("reading driver home directory %q: %w" , d .home , err )
1429- }
1430- // This makes the link directory if it doesn't exist
1431- if err := idtools .MkdirAllAndChown (path .Join (d .home , linkDir ), 0o755 , idtools.IDPair {UID : 0 , GID : 0 }); err != nil {
1432- return err
1433- }
1434- // Keep looping as long as we take some corrective action in each iteration
1435- var errs error
1436- madeProgress := true
1437- iterations := 0
1438- for madeProgress {
1439- errs = nil
1440- madeProgress = false
1441- // Check that for each layer, there's a link in "l" with the name in
1442- // the layer's "link" file that points to the layer's "diff" directory.
1443- for _ , dir := range dirs {
1444- // Skip over the linkDir, stagingDir, tempDirName and anything that is not a directory
1445- if dir .Name () == linkDir || dir .Name () == stagingDir || dir .Name () == tempDirName || ! dir .IsDir () {
1446- continue
1447- }
1448- // Read the "link" file under each layer to get the name of the symlink
1449- data , err := os .ReadFile (path .Join (d .dir (dir .Name ()), "link" ))
1450- if err != nil {
1451- errs = errors .Join (errs , fmt .Errorf ("reading name of symlink for %q: %w" , dir .Name (), err ))
1452- continue
1453- }
1454- linkPath := path .Join (d .home , linkDir , strings .Trim (string (data ), "\n " ))
1455- // Check if the symlink exists, and if it doesn't, create it again with the
1456- // name we got from the "link" file
1457- err = fileutils .Lexists (linkPath )
1458- if err != nil && errors .Is (err , fs .ErrNotExist ) {
1459- if err := os .Symlink (path .Join (".." , dir .Name (), "diff" ), linkPath ); err != nil {
1460- errs = errors .Join (errs , err )
1461- continue
1462- }
1463- madeProgress = true
1464- } else if err != nil {
1465- errs = errors .Join (errs , err )
1466- continue
1467- }
1468- }
1469-
1470- // linkDirFullPath is the full path to the linkDir
1471- linkDirFullPath := filepath .Join (d .home , "l" )
1472- // Now check if we somehow lost a "link" file, by making sure
1473- // that each symlink we have corresponds to one.
1474- links , err := os .ReadDir (linkDirFullPath )
1475- if err != nil {
1476- errs = errors .Join (errs , err )
1477- continue
1478- }
1479- // Go through all of the symlinks in the "l" directory
1480- for _ , link := range links {
1481- // Read the symlink's target, which should be "../$layer/diff"
1482- target , err := os .Readlink (filepath .Join (linkDirFullPath , link .Name ()))
1483- if err != nil {
1484- errs = errors .Join (errs , err )
1485- continue
1486- }
1487- targetComponents := strings .Split (target , string (os .PathSeparator ))
1488- if len (targetComponents ) != 3 || targetComponents [0 ] != ".." || targetComponents [2 ] != "diff" {
1489- errs = errors .Join (errs , fmt .Errorf ("link target of %q looks weird: %q" , link , target ))
1490- // force the link to be recreated on the next pass
1491- if err := os .Remove (filepath .Join (linkDirFullPath , link .Name ())); err != nil {
1492- if ! errors .Is (err , fs .ErrNotExist ) {
1493- errs = errors .Join (errs , fmt .Errorf ("removing link %q: %w" , link , err ))
1494- } // else don’t report any error, but also don’t set madeProgress.
1495- continue
1496- }
1497- madeProgress = true
1498- continue
1499- }
1500- // Reconstruct the name of the target's link file and check that
1501- // it has the basename of our symlink in it.
1502- targetID := targetComponents [1 ]
1503- linkFile := filepath .Join (d .dir (targetID ), "link" )
1504- data , err := os .ReadFile (linkFile )
1505- if err != nil || string (data ) != link .Name () {
1506- // NOTE: If two or more links point to the same target, we will update linkFile
1507- // with every value of link.Name(), and set madeProgress = true every time.
1508- if err := os .WriteFile (linkFile , []byte (link .Name ()), 0o644 ); err != nil {
1509- errs = errors .Join (errs , fmt .Errorf ("correcting link for layer %s: %w" , targetID , err ))
1510- continue
1511- }
1512- madeProgress = true
1513- }
1514- }
1515- iterations ++
1516- if iterations >= maxIterations {
1517- errs = errors .Join (errs , fmt .Errorf ("reached %d iterations in overlay graph driver’s recreateSymlink, giving up" , iterations ))
1518- break
1519- }
1520- }
1521- return errs
1522- }
1523-
15241449// Get creates and mounts the required file system for the given id and returns the mount path.
15251450func (d * Driver ) Get (id string , options graphdriver.MountOpts ) (string , error ) {
15261451 return d .get (id , false , options )
@@ -1615,9 +1540,15 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
16151540 readWrite = false
16161541 }
16171542
1618- lowers , err := os .ReadFile (path .Join (dir , lowerFile ))
1619- if err != nil && ! errors .Is (err , fs .ErrNotExist ) {
1620- return "" , err
1543+ lowers , err := os .ReadFile (path .Join (dir , lowerLayersFile ))
1544+ if err != nil {
1545+ if ! errors .Is (err , unix .ENOENT ) {
1546+ return "" , err
1547+ }
1548+ lowers , err = os .ReadFile (path .Join (dir , lowerFile ))
1549+ if err != nil && ! os .IsNotExist (err ) {
1550+ return "" , err
1551+ }
16211552 }
16221553 splitLowers := strings .Split (string (lowers ), ":" )
16231554 if len (splitLowers ) > maxDepth {
@@ -1729,16 +1660,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
17291660 }
17301661 lower = ""
17311662 }
1732- // if it is a "not found" error, that means the symlinks were lost in a sudden reboot
1733- // so call the recreateSymlinks function to go through all the layer dirs and recreate
1734- // the symlinks with the name from their respective "link" files
1735- if lower == "" && errors .Is (err , fs .ErrNotExist ) {
1736- logrus .Warnf ("Can't stat lower layer %q because it does not exist. Going through storage to recreate the missing symlinks." , newpath )
1737- if err := d .recreateSymlinks (); err != nil {
1738- return "" , fmt .Errorf ("recreating the missing symlinks: %w" , err )
1739- }
1740- lower = newpath
1741- } else if lower == "" {
1663+ if lower == "" {
17421664 return "" , fmt .Errorf ("can't stat lower layer %q: %w" , newpath , err )
17431665 }
17441666 } else {
@@ -1751,7 +1673,12 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
17511673
17521674 linkContent , err := os .Readlink (lower )
17531675 if err != nil {
1754- return "" , err
1676+ if ! errors .Is (err , syscall .EINVAL ) {
1677+ return "" , err
1678+ }
1679+ // Not a symlink: layer ID from lower-layers, append /diff.
1680+ lower = path .Join (lower , "diff" )
1681+ linkContent = lower
17551682 }
17561683 lowerID := filepath .Base (filepath .Dir (linkContent ))
17571684 composefsMount , err := maybeAddComposefsMount (lowerID , i + 1 , readWrite )
0 commit comments