aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Purdie <richard.purdie@linuxfoundation.org>2021-06-30 13:12:14 +0100
committerAlexandre Belloni <alexandre.belloni@bootlin.com>2021-07-01 18:57:16 +0200
commitec58333b3218b7ae890b4e69fd28c4dadb241474 (patch)
tree8a0490de9d462278a0af370d600f17b6f63268dc
parentdb6a9d860f8f5335265433be0b237e26f3167ca8 (diff)
downloadopenembedded-core-contrib-ec58333b3218b7ae890b4e69fd28c4dadb241474.tar.gz
openembedded-core-contrib-ec58333b3218b7ae890b4e69fd28c4dadb241474.tar.bz2
openembedded-core-contrib-ec58333b3218b7ae890b4e69fd28c4dadb241474.zip
sstate/staging: Handle directory creation race issue
The sstate code tries to be careful about racing around directory creation. In particular, the copyhardlinktree code creates the directory tree first allowing for "already exists" errors and ignoring them, then hardlinks the files in. Unfortunately the sstate removal code can race against this since it will try and remove empty directories. If there is some bad timing, a newly created directory can be removed before it was populated, leading to build failures. We could try and add locking but this would damage performance, we've been there before. It is also unclear where to actually place locks just based on the contents of a manifest file which may cover multiple sstate install locations for a given task. Instead, lets disable directory removal in the problematic "shared" core path. This could result in a few more empty directories being left on disk but those should be harmless and better than locking hurting performance or rare build races. [YOCTO #13999] [YOCTO #14379] Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org> Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
-rw-r--r--meta/classes/sstate.bbclass8
-rw-r--r--meta/classes/staging.bbclass6
2 files changed, 8 insertions, 6 deletions
diff --git a/meta/classes/sstate.bbclass b/meta/classes/sstate.bbclass
index 72eebd70c91..6c8e64ed00d 100644
--- a/meta/classes/sstate.bbclass
+++ b/meta/classes/sstate.bbclass
@@ -483,7 +483,7 @@ def sstate_clean_cachefiles(d):
ss = sstate_state_fromvars(ld, task)
sstate_clean_cachefile(ss, ld)
-def sstate_clean_manifest(manifest, d, prefix=None):
+def sstate_clean_manifest(manifest, d, canrace=False, prefix=None):
import oe.path
mfile = open(manifest)
@@ -501,7 +501,9 @@ def sstate_clean_manifest(manifest, d, prefix=None):
if entry.endswith("/"):
if os.path.islink(entry[:-1]):
os.remove(entry[:-1])
- elif os.path.exists(entry) and len(os.listdir(entry)) == 0:
+ elif os.path.exists(entry) and len(os.listdir(entry)) == 0 and not canrace:
+ # Removing directories whilst builds are in progress exposes a race. Only
+ # do it in contexts where it is safe to do so.
os.rmdir(entry[:-1])
else:
os.remove(entry)
@@ -539,7 +541,7 @@ def sstate_clean(ss, d):
for lock in ss['lockfiles']:
locks.append(bb.utils.lockfile(lock))
- sstate_clean_manifest(manifest, d)
+ sstate_clean_manifest(manifest, d, canrace=True)
for lock in locks:
bb.utils.unlockfile(lock)
diff --git a/meta/classes/staging.bbclass b/meta/classes/staging.bbclass
index 806a85773af..29005ac0b62 100644
--- a/meta/classes/staging.bbclass
+++ b/meta/classes/staging.bbclass
@@ -409,7 +409,7 @@ python extend_recipe_sysroot() {
if os.path.islink(f) and not os.path.exists(f):
bb.note("%s no longer exists, removing from sysroot" % f)
lnk = os.readlink(f.replace(".complete", ""))
- sstate_clean_manifest(depdir + "/" + lnk, d, workdir)
+ sstate_clean_manifest(depdir + "/" + lnk, d, True, workdir)
os.unlink(f)
os.unlink(f.replace(".complete", ""))
@@ -454,7 +454,7 @@ python extend_recipe_sysroot() {
fl = depdir + "/" + l
bb.note("Task %s no longer depends on %s, removing from sysroot" % (mytaskname, l))
lnk = os.readlink(fl)
- sstate_clean_manifest(depdir + "/" + lnk, d, workdir)
+ sstate_clean_manifest(depdir + "/" + lnk, d, True, workdir)
os.unlink(fl)
os.unlink(fl + ".complete")
@@ -475,7 +475,7 @@ python extend_recipe_sysroot() {
continue
else:
bb.note("%s exists in sysroot, but is stale (%s vs. %s), removing." % (c, lnk, c + "." + taskhash))
- sstate_clean_manifest(depdir + "/" + lnk, d, workdir)
+ sstate_clean_manifest(depdir + "/" + lnk, d, True, workdir)
os.unlink(depdir + "/" + c)
if os.path.lexists(depdir + "/" + c + ".complete"):
os.unlink(depdir + "/" + c + ".complete")