Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/devices/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ utils = { path = "../utils" }
polly = { path = "../polly" }
rutabaga_gfx = { path = "../rutabaga_gfx", features = ["virgl_renderer", "virgl_renderer_next"], optional = true }
imago = { version = "0.1.4", features = ["sync-wrappers", "vm-memory"] }
rustix = { version = "1.1.2", features = ["fs"] }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think adding a new dependency just for this is a bit overkill. Let's simply wait for the rust toolchain to ship a newer version of musl, shouldn't take long.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, adding the dependency for such a simple thing seems like an overkill to me too.

An alternative could be to use libc::syscall directly.

musl 1.2.5 was released on February 29, 2024, so it's taking a while 😄. Nevertheless seems like we will get it soon-ish:
rust-lang/rust#142682

Btw. I was actually considering whether we may want to start using rustix over nix - it seemed to be nicer in some areas than nix, but it's hard to say...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

statx-sys does that, but has been deprecated in favor of libc::statx and rustix. It doesn't support stx_mnt_id but can be patched easily. But we could use it, thereby avoiding pulling in rustix and also writing the wrapper from scratch.

I created a draft here:

I'd move the statx-sys fork to libkrun or just include the files in the project if we wanna go forward with this.


[target.'cfg(target_os = "macos")'.dependencies]
hvf = { path = "../hvf" }
Expand Down
76 changes: 36 additions & 40 deletions src/devices/src/virtio/fs/linux/passthrough.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,52 +147,48 @@ fn stat(f: &File) -> io::Result<libc::stat64> {
}

fn statx(f: &File) -> io::Result<(libc::stat64, u64)> {
let mut stx = MaybeUninit::<libc::statx>::zeroed();
use rustix::fd::BorrowedFd;
use rustix::fs::{statx, AtFlags, StatxFlags};

// Safe because this is a constant value and a valid C string.
let pathname = unsafe { CStr::from_bytes_with_nul_unchecked(EMPTY_CSTR) };
let dirfd = unsafe { BorrowedFd::borrow_raw(f.as_raw_fd()) };

// Safe because the kernel will only write data in `st` and we check the return
// value.
let res = unsafe {
libc::statx(
f.as_raw_fd(),
pathname.as_ptr(),
libc::AT_EMPTY_PATH | libc::AT_SYMLINK_NOFOLLOW,
libc::STATX_BASIC_STATS | libc::STATX_MNT_ID,
stx.as_mut_ptr(),
)
};
if res >= 0 {
// Safe because the kernel guarantees that the struct is now fully initialized.
let stx = unsafe { stx.assume_init() };

// Unfortunately, we cannot use an initializer to create the stat64 object,
// because it may contain padding and reserved fields (depending on the
// architecture), and it does not implement the Default trait.
// So we take a zeroed struct and set what we can. (Zero in all fields is
// wrong, but safe.)
let mut st = unsafe { MaybeUninit::<libc::stat64>::zeroed().assume_init() };

st.st_dev = libc::makedev(stx.stx_dev_major, stx.stx_dev_minor);
st.st_ino = stx.stx_ino;
st.st_mode = stx.stx_mode as _;
st.st_nlink = stx.stx_nlink as _;
st.st_uid = stx.stx_uid;
st.st_gid = stx.stx_gid;
st.st_rdev = libc::makedev(stx.stx_rdev_major, stx.stx_rdev_minor);
st.st_size = stx.stx_size as _;
st.st_blksize = stx.stx_blksize as _;
st.st_blocks = stx.stx_blocks as _;
st.st_atime = stx.stx_atime.tv_sec;
st.st_atime_nsec = stx.stx_atime.tv_nsec as _;
st.st_mtime = stx.stx_mtime.tv_sec;
st.st_mtime_nsec = stx.stx_mtime.tv_nsec as _;
st.st_ctime = stx.stx_ctime.tv_sec;
st.st_ctime_nsec = stx.stx_ctime.tv_nsec as _;
Ok((st, stx.stx_mnt_id))
} else {
Err(io::Error::last_os_error())
match statx(
dirfd,
pathname,
AtFlags::EMPTY_PATH | AtFlags::SYMLINK_NOFOLLOW,
StatxFlags::BASIC_STATS | StatxFlags::MNT_ID,
) {
Ok(stx) => {
// Unfortunately, we cannot use an initializer to create the stat64 object,
// because it may contain padding and reserved fields (depending on the
// architecture), and it does not implement the Default trait.
// So we take a zeroed struct and set what we can. (Zero in all fields is
// wrong, but safe.)
let mut st = unsafe { MaybeUninit::<libc::stat64>::zeroed().assume_init() };

st.st_dev = libc::makedev(stx.stx_dev_major, stx.stx_dev_minor);
st.st_ino = stx.stx_ino;
st.st_mode = stx.stx_mode as _;
st.st_nlink = stx.stx_nlink as _;
st.st_uid = stx.stx_uid;
st.st_gid = stx.stx_gid;
st.st_rdev = libc::makedev(stx.stx_rdev_major, stx.stx_rdev_minor);
st.st_size = stx.stx_size as _;
st.st_blksize = stx.stx_blksize as _;
st.st_blocks = stx.stx_blocks as _;
st.st_atime = stx.stx_atime.tv_sec;
st.st_atime_nsec = stx.stx_atime.tv_nsec as _;
st.st_mtime = stx.stx_mtime.tv_sec;
st.st_mtime_nsec = stx.stx_mtime.tv_nsec as _;
st.st_ctime = stx.stx_ctime.tv_sec;
st.st_ctime_nsec = stx.stx_ctime.tv_nsec as _;
Ok((st, stx.stx_mnt_id))
}
Err(e) => Err(e.into()),
}
}

Expand Down