Skip to content

Windows host: renaming a file on a bind mount makes it unusable in the guest until sandbox restart #1638

Description

@albertsikkema-elix

Environment

  • msb v0.7.2 (msb update reports latest), libkrunfw bundled
  • Windows 11 Pro 10.0.26100, x86_64, physical machine (Lenovo), Windows Hypervisor Platform
  • msb doctor: clean (only warning: no reflink on MSB_HOME)
  • Guest image: alpine

Repro

mkdir C:\spike\trace2
msb create alpine --name trace2 --mount-dir C:\spike\trace2:/w
msb exec trace2 -- sh -c "cd /w; echo a > f; cat f; mv f h; echo rc=`$?; cat h; ls -la"

Expected: a, rc=0, a, then a listing containing h.

Actual:

a
rc=0
cat: can't open 'h': I/O error
total 0
  • Creating and reading a file works. Any rename breaks it: to a new name, over an existing file (mv -f), and directory renames (mv d1 d2; cat d2/in gives Invalid argument).
  • After the rename, the whole directory lists as empty (total 0), not just the renamed entry.
  • The error persists after echo 3 > /proc/sys/vm/drop_caches in the guest and in a new msb exec session.
  • msb stop + msb start fixes it: the file is then readable and listed correctly.
  • A second sandbox mounting the same folder sees the correct state.

Host side is intact. After the failing rename, on Windows:

  • h exists with the correct content, and f is gone.
  • The msb.override_stat ADS moved with the file (20 bytes).
  • An exclusive [IO.File]::Open(h, 'Open', 'ReadWrite', 'None') succeeds, so no process holds a handle on it.
  • Defender real-time protection is off, so AV interference is ruled out.

So the state that goes wrong appears to be the backend's in-memory inode state, not the host file or the guest's caches.

Tried every mount option: stat-virt=strict, relaxed and off, plus host-perms=mirror,uid=1000,gid=1000. All fail the same way.

Impact: git cannot work on a Windows bind mount, because it writes a lock file and renames it over the original. git init and git clone fail with:

warning: unable to access '/workspace/gitrepo/.git/config': I/O error
fatal: unknown error occurred while reading the configuration files

The same commands work on the guest's own rootfs.

Possibly relevant code (v0.7.2), from reading the source rather than debugging, so these are leads, not a confirmed cause:

  • passthroughfs/windows/ops.rs:180 (rename) → remove_ops.rs:99 (rename_inode_path). Every later op resolves files through the cached InodeData.path, so a stale entry here would produce exactly this "broken until restart" behaviour.
  • remove_ops.rs:110: cached descendants of a renamed directory are only re-pathed when owned_checkpoint is set. That fits the mv d1 d2; cat d2/in failure on a plain bind mount.
  • dir_ops.rs:88-110: dir_entries returns early on the first failing child, which would explain one broken entry making the whole directory appear empty.
  • mod.rs:726 (host_error): unmapped Windows errors become EIO, which hides the underlying Windows error. Logging the raw error there would probably pinpoint this quickly.
  • The existing heartbeat_style_rename_keeps_source_inode_usable test renames host-created files using the fs_for config. The runtime builds bind mounts differently (runner/vm.rs:2290: external_checkpoint: Some(..), no_symlink_root: true), and the failing case here is a guest-created file.

Possibly related: #1559 (hard links on bind mounts). Hard links also fail on this host (ln g hard → I/O error), and symlinks created in the guest show up as 1-byte regular files on the Windows side.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions