From 3731208dc120b5d12f1c5c63ec58bcdb34c42195 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 24 Jul 2023 16:54:14 -0400 Subject: [PATCH 1/2] Adopt GC test for local-overlay store Doesn't yet pass. Fixes are needed. --- tests/overlay-local-store/gc-inner.sh | 57 +++++++++++++++++++++++++++ tests/overlay-local-store/gc.sh | 5 +++ tests/overlay-local-store/local.mk | 1 + 3 files changed, 63 insertions(+) create mode 100644 tests/overlay-local-store/gc-inner.sh create mode 100755 tests/overlay-local-store/gc.sh diff --git a/tests/overlay-local-store/gc-inner.sh b/tests/overlay-local-store/gc-inner.sh new file mode 100644 index 000000000..01ec48b84 --- /dev/null +++ b/tests/overlay-local-store/gc-inner.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +set -eu -o pipefail + +source common.sh + +# Avoid store dir being inside sandbox build-dir +unset NIX_STORE_DIR +unset NIX_STATE_DIR + +storeDirs + +initLowerStore + +mountOverlayfs + +export NIX_REMOTE="$storeB" +stateB="$storeBRoot/nix/var/nix" +outPath=$(nix-build ../hermetic.nix --no-out-link --arg busybox "$busybox" --arg seed 2) + +# Set a GC root. +mkdir -p "$stateB" +rm -f "$stateB"/gcroots/foo +ln -sf $outPath "$stateB"/gcroots/foo + +[ "$(nix-store -q --roots $outPath)" = "$stateB/gcroots/foo -> $outPath" ] + +nix-store --gc --print-roots | grep $outPath +nix-store --gc --print-live | grep $outPath +if nix-store --gc --print-dead | grep -E $outPath$; then false; fi + +nix-store --gc --print-dead + +expect 1 nix-store --delete $outPath +test -e "$storeBRoot/$outPath" + +shopt -s nullglob +for i in $storeBRoot/*; do + if [[ $i =~ /trash ]]; then continue; fi # compat with old daemon + touch $i.lock + touch $i.chroot +done + +nix-collect-garbage + +# Check that the root and its dependencies haven't been deleted. +cat "$storeBRoot/$outPath" + +rm "$stateB"/gcroots/foo + +nix-collect-garbage + +# Check that the output has been GC'd. +test ! -e $outPath + +# Check that the store is empty. +[ "$(ls -1 "$storeBTop" | wc -l)" = "0" ] diff --git a/tests/overlay-local-store/gc.sh b/tests/overlay-local-store/gc.sh new file mode 100755 index 000000000..1e1fb203e --- /dev/null +++ b/tests/overlay-local-store/gc.sh @@ -0,0 +1,5 @@ +source common.sh + +requireEnvironment +setupConfig +execUnshare ./gc-inner.sh diff --git a/tests/overlay-local-store/local.mk b/tests/overlay-local-store/local.mk index 3a6d00bc1..1f8de8f27 100644 --- a/tests/overlay-local-store/local.mk +++ b/tests/overlay-local-store/local.mk @@ -4,6 +4,7 @@ overlay-local-store-tests := \ $(d)/build.sh \ $(d)/bad-uris.sh \ $(d)/add-lower.sh \ + $(d)/gc.sh \ $(d)/verify.sh \ $(d)/optimise.sh From 9ef0a9e8aa2e27991434c104ad73b1b95b241f08 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Tue, 25 Jul 2023 10:28:11 -0400 Subject: [PATCH 2/2] Fix hard linking issue causing overlay fs copy-ups --- src/libstore/build/local-derivation-goal.cc | 7 ++++--- src/libstore/local-fs-store.hh | 10 ++++++++++ src/libstore/local-overlay-store.cc | 7 +++++++ src/libstore/local-overlay-store.hh | 2 ++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index b7a27490c..3bc88ee86 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -386,8 +386,9 @@ void LocalDerivationGoal::cleanupPostOutputsRegisteredModeNonCheck() #if __linux__ -static void linkOrCopy(const Path & from, const Path & to) +static void linkOrCopy(LocalFSStore & store, const StorePath & from_, const Path & to) { + auto from = store.toRealPathForHardLink(from_); if (link(from.c_str(), to.c_str()) == -1) { /* Hard-linking fails if we exceed the maximum link count on a file (e.g. 32000 of ext3), which is quite possible after a @@ -712,7 +713,7 @@ void LocalDerivationGoal::startBuilder() if (S_ISDIR(lstat(r).st_mode)) dirsInChroot.insert_or_assign(p, r); else - linkOrCopy(r, chrootRootDir + p); + linkOrCopy(getLocalStore(), i, chrootRootDir + p); } /* If we're repairing, checking or rebuilding part of a @@ -1574,7 +1575,7 @@ void LocalDerivationGoal::addDependency(const StorePath & path) throw Error("could not add path '%s' to sandbox", worker.store.printStorePath(path)); } else - linkOrCopy(source, target); + linkOrCopy(getLocalStore(), path, target); #else throw Error("don't know how to make path '%s' (produced by a recursive Nix call) appear in the sandbox", diff --git a/src/libstore/local-fs-store.hh b/src/libstore/local-fs-store.hh index 488109501..19858f5c8 100644 --- a/src/libstore/local-fs-store.hh +++ b/src/libstore/local-fs-store.hh @@ -73,6 +73,16 @@ public: return getRealStoreDir() + "/" + std::string(storePath, storeDir.size() + 1); } + /** + * If the real path is hardlinked with something else, we might + * prefer to refer to the other path instead. This is the case with + * overlayfs, for example. + */ + virtual Path toRealPathForHardLink(const StorePath & storePath) + { + return Store::toRealPath(storePath); + } + std::optional getBuildLogExact(const StorePath & path) override; }; diff --git a/src/libstore/local-overlay-store.cc b/src/libstore/local-overlay-store.cc index 700a5227b..47d09dc75 100644 --- a/src/libstore/local-overlay-store.cc +++ b/src/libstore/local-overlay-store.cc @@ -209,6 +209,13 @@ void LocalOverlayStore::optimiseStore() } } +Path LocalOverlayStore::toRealPathForHardLink(const StorePath & path) +{ + return lowerStore->isValidPath(path) + ? lowerStore->Store::toRealPath(path) + : Store::toRealPath(path); +} + static RegisterStoreImplementation regLocalOverlayStore; } diff --git a/src/libstore/local-overlay-store.hh b/src/libstore/local-overlay-store.hh index 349d9e6ed..64e2ef488 100644 --- a/src/libstore/local-overlay-store.hh +++ b/src/libstore/local-overlay-store.hh @@ -114,6 +114,8 @@ private: void deleteGCPath(const Path & path, uint64_t & bytesFreed) override; void optimiseStore() override; + + Path toRealPathForHardLink(const StorePath & storePath) override; }; }