-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use a union source accessor to put chroot stores in the logical location #12512
Conversation
I believe this does fix the problem! Though when I tried it out, the installer test failed with a different issue:
full error
To test this I used
with following (non-reproducible) diff (which includes changing the Nix version for the test, and reverts NixOS/nixpkgs#369459) on a recent Nixpkgs version: diffdiff --git a/nixos/tests/installer.nix b/nixos/tests/installer.nix
index 6be3346d9850..4b4e12ccd73b 100644
--- a/nixos/tests/installer.nix
+++ b/nixos/tests/installer.nix
@@ -761,6 +761,7 @@ let
++ optionals clevisTest [ pkgs.klibc ]
++ optional systemdStage1 pkgs.chroot-realpath;
+ nix.package = (builtins.getFlake "github:DeterminateSystems/nix-src/store-fs").outputs.packages.x86_64-linux.default;
nix.settings = {
substituters = mkForce [ ];
hashed-mirrors = null;
diff --git a/pkgs/by-name/ni/nixos-firewall-tool/package.nix b/pkgs/by-name/ni/nixos-firewall-tool/package.nix
index b928487c5277..a5493d495876 100644
--- a/pkgs/by-name/ni/nixos-firewall-tool/package.nix
+++ b/pkgs/by-name/ni/nixos-firewall-tool/package.nix
@@ -6,10 +6,13 @@
shellcheck-minimal,
}:
-stdenvNoCC.mkDerivation {
+stdenvNoCC.mkDerivation rec {
name = "nixos-firewall-tool";
- src = builtins.filterSource (name: _: !(lib.hasSuffix ".nix" name)) ./.;
+ src = lib.fileset.toSource {
+ root = ./.;
+ fileset = lib.fileset.fileFilter (file: !file.hasExt "nix") ./.;
+ };
strictDeps = true;
buildInputs = [ bash ]; |
The tests do expose a problem with
and
I suppose we can add a hack to make the root of |
An alternate solution is to mount the logical store as an overlay-mounted onto |
That wouldn't work for the case where we're accessing files in both the physical and logical Nix store. For instance, the test case in #11503 is evaluating a |
It would have to be an overlay mount, not a normal mount. That way you get a store path from either of the underlying file systems. I don't think we need to care about which one, as long as it can find a path that exists. I suppose it might resolve a store path to the wrong fs, if it exists in both, which might be weird if it's an input addressed path with an impurity, or when it picks the one on a worse file system (e.g. case insensitive), but besides those corner cases, it seems like it'd be pretty good at picking a path that exists. |
The CanonPath constructor already does that.
Hopefully fixes NixOS#11503.
src/libexpr/eval.cc
Outdated
evaluating a file from the physical /nix/store while | ||
using a chroot store. */ | ||
auto realStoreDir = dirOf(store->toRealPath(StorePath::dummy)); | ||
if (store->storeDir != realStoreDir) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'll want this always
- for simplicity
- in order to expose chroot-store bugs sooner
- in preparation for other stores, e.g. an in-memory or write caching store wrapper for performance
- eventually for Case-hacked files are observable from the language #9319
if (store->storeDir != realStoreDir) { |
If we're not confident, I'd want a flag to make it unconditional so the team and any other volunteers can dogfood it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test suite succeeds with this enabled unconditionally, but for performance I don't think we should always enable it. For instance, every maybeLstat()
call will now result in two maybeLstat()
calls to the underlying accessors if the file doesn't exist. Though since PosixSourceAccessor
has some caching it's probably not too bad.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't read the code yet, but "double lstat" sounds like the wrong solution to me. We need to stop assuming the store is accessible within rootFS
at all if we want both good performance and hygiene.
src/libexpr/eval.cc
Outdated
auto storeFS = makeMountedSourceAccessor( | ||
{ | ||
{CanonPath::root, makeEmptySourceAccessor()}, | ||
{CanonPath(store->storeDir), makeFSSourceAccessor(realStoreDir)} | ||
}); | ||
accessor = makeUnionSourceAccessor({accessor, storeFS}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we use Store::getFSAccessor
for this? Also I want Store::getFSAccessor
to be rooted int the store dir. I don't like all these "union in place" things that both this and Store::getFSAccessor
do. I want to do CanonPath(storePath.to_string())
and have that just work with storeFS
(note that the canon path will be e.g. w4l4xvw461ywc4ia3accj5i3hh50n4r8-nix-2.24.1
in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CC @puffnfresh who I have been talking to about this same stuff
@infinisil I think that error is coming from Nix 2.24.12, since that's what the installed NixOS system in the VM has. |
It's no longer needed now that all store paths inside the evaluator are logical rather than real paths.
Note that in pure mode, we don't need to use the union FS even when using a chroot store, since the user shouldn't have access to the physical /nix/store.
Nix Meeting #214 notes:
Some thoughts from me, paraphrasing the long discussion: I like this path a lot. Here is my thinking: Background: I like designs which are more I think that whatever we do for this bug fix would be tantamount to an instant-stable experimental feature. So I was concerned to have in all code-paths a complex mounting-based fix. This would be more design debt in the name of back-compat getting us further way from a nice capability-based design. At the same time, @edolstra convinced me that not doing the union mechanism was unworkable breakage in the general case. The issue is I had forgotten about However, in the pure-eval case, we don't do arbitrary file access. So while we still have the situation of many path values within the store, we only have that situation --- not arbitrary root-FS paths. That means that --- for somewhat opposite reasons than I initially realized --- we can without breakage avoid a union FS in the pure-eval case. This make me quite happy that we can achieve all goals:
So in conclusion, horray! I was quite nervous about all this, and now I feel quite the opposite :). |
path = {state.rootFS, CanonPath(state.toRealPath(rewriteStrings(path.path.abs(), rewrites), context))}; | ||
|
||
try { | ||
auto [storePath, subPath] = state.store->toStorePath(path.path.abs()); | ||
// FIXME: we should scanForReferences on the path before adding it | ||
refs = state.store->queryPathInfo(storePath)->references; | ||
path = {state.rootFS, CanonPath(state.store->toRealPath(storePath) + subPath)}; | ||
} catch (Error &) { // FIXME: should be InvalidPathError | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the idea that refs
is unused? If so, let's also delete the variable above? If not... what's going on?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a regression in....ea38605?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this appears to be dead code. I think the idea was to propagate the references, but that "feature" was never really well thought out. Maybe we should warn/fail if the path has references...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can investigate what happened here later. IIRC there was some regressions with this too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good modulo the one question
(all but approval :))
@infinisil btw I tested this with the nixpkgs installer test using these changes: NixOS/nixpkgs@master...ElvishJerricco:nixpkgs:push-uysonulrlluq I reverted the nixos-firewall-tools filesets thing and changed the revision of nix 2.26 to this merge revision, but I had to also add the nix package's That's why you got that error. Adding |
Motivation
When using a chroot store, paths that are in the chroot store (such as those resulting from IFD or similar) should be represented in the evaluator using their logical path (e.g.
/nix/store/foo
), not their physical path (e.g./tmp/chroot/nix/store/foo
). This PR does that - it removes all uses oftoRealPath()
in the evaluator. To make chroot stores still work, the physical store path is "mounted" onto the logical store location ofrootFS
. And to handle the case where we also need to access a file in the real/nix/store
, we use a union source accessor that provides a union view of the two stores.Fixes #11503.
Context
Add 👍 to pull requests you find important.
The Nix maintainer team uses a GitHub project board to schedule and track reviews.