-
Couldn't load subscription status.
- Fork 221
Add mount_setattr
#1002
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
base: main
Are you sure you want to change the base?
Add mount_setattr
#1002
Conversation
396991e to
78c5696
Compare
78c5696 to
2f77562
Compare
| #[derive(Debug, Copy, Clone)] | ||
| #[allow(missing_docs)] | ||
| pub struct MountAttr<'a> { | ||
| pub attr_set: MountAttrFlags, |
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.
According to Linux's documentation, attr_set is a __u64, while MountAttrFlags is currently a c_uint. Could you add a test testing that the layout matches, following one of the "layouts" tests in the tree?
If you don't have a need for it at this time, then we don't need to. If someone later has a need for it, we can add another function that exposes 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.
I would like to help to finish this pull-request, in case @yujincheng08 can't continue it.
| pub attr_set: MountAttrFlags, | ||
| pub attr_clr: MountAttrFlags, | ||
| pub propagation: MountPropagationFlags, | ||
| pub userns_fd: BorrowedFd<'a>, |
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.
userns_fd field is expected as a __u64, but BorrowedFd is 4 bytes. Maybe it is safer to declare a private struct with the exact same fields of the C API, and translate the MountAttr fields to it before calling mount_setattr.
#[repr(C)]
pub(crate) struct mount_attr {
pub attr_set: u64,
pub attr_clr: u64,
pub propagation: u64,
pub userns_fd: u64,
}Also, userns_fd is needed only when attr_set includes MOUNT_ATTR_IDMAP. The field could be declared as an Option<BorrowedFd<'a>>, and send it as -EBADFD to the syscall if it is None.
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.
Maybe it is safer to declare a private struct with the exact same fields of the C API, and translate the MountAttr fields to it before calling mount_setattr.
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 that the way mount_attr is defined in lnix is better than exposing the fields directly.
The usage would be something like this:
mount_setattr(
dir_fd,
c"",
MountSetattrFlags::RECURSIVE | MountSetattrFlags::EMPTY_PATH,
MountAttr::new().set_flags(MountAttrFlags::RDONLY),
)?;@sunfishcode Do you want to take the same approach from lnix?
I can implement the changes if needed.
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.
How is userns_fd exposed in the lnix API?
In general, I'm in favor of encapsulating these fields like this, provided we can do so without restricting useful functionality.
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.
How is
userns_fdexposed in the lnix API?
It seems that it does not support setting values to userns_fd (there is a TODO: ID-mapped mounts, and userns_fd only appears in the struct definition).
mount_setattr() will not close the file descriptor. I guess that MountAttr should take the ownership of the file descriptor, so it can guarantee that the descriptor is valid when mount_setattr is called, and closed when MountAttr is not needed anymore.
Maybe something like this:
pub struct MountAttr {
mount_attr: sys::mount_attr,
userns_fd: Option<OwnedFd>,
}
impl MountAttr {
pub fn set_userns_fd(&mut self, userns_fd: OwnedFd) -> &mut Self {
self.mount_attr.userns_fd = userns_fd.as_raw_fd() as u64;
self.userns_fd = Some(userns_fd);
self
}
// ...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.
It seems to me like the current struct-based approach was done as an implementation detail at the syscall level to allow extensibility in the future. I wouldn't see anything wrong with a simple implementation of this API using only (an admittedly large number of) function parameters: dirfd, pathname, flags, set, clear, propagation, userns.
We could even imagine specialized cases similar to what is done for other mount APIs (like how the mount syscall is exposed also as mount_remount, or there are many typesafe fsconfig variants).
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.
It seems to me like the current struct-based approach was done as an implementation detail at the syscall level to allow extensibility in the future. I wouldn't see anything wrong with a simple implementation of this API using only (an admittedly large number of) function parameters: dirfd, pathname, flags, set, clear, propagation, userns.
Well this would mean rustix needs a semver bump or a new function if the kernel adds a new field.
We could even imagine specialized cases similar to what is done for other mount APIs (like how the mount syscall is exposed also as mount_remount, or there are many typesafe fsconfig variants).
There is one difference, the mount functions you listed have an multiplexed interface that got demultiplexed by rustix. mount_setattr isn't a multiplexed syscall (in that form) so splitting would mean you need multiple syscalls instead of one.
Summarizing my thought, we should first decided whether we want extensibility in the future (w/o breaking) or not.
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 see it as a matter of pragmatism: this would be an easy way to resolve this issue in the short term...
Should the API ever change, then there would be a lot of options at that point, including adding a complex API that takes a struct...
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.
It seems to me like the current
struct-based approach was done as an implementation detail at the syscall level to allow extensibility in the future.
An advantage of using a struct is that it is easier to omit default fields with dedicated builder functions. For example, with the draft in #1002 (comment), an ID-mapped mount could be created with:
use MountSetAttrFlags as Flags;
mount_setattr(
dir_fd,
c"",
Flags::RECURSIVE | Flags::EMPTY_PATH,
MountAttr::new_with_idmap(userns),
)?;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.
openat2has a future extensibility struct that rustix decided to inline into the function signature.clone3has a future extensibility struct but is impossible to be implemented by rustix.mount_setattr,sched_setattr,landlock_create_ruleset,statmount/listmount,perf_event_openhave a future extensibility struct and are not yet implemented by rustix.
So we are not dealing with a single syscall but also with the design future syscalls in rustix might follow.
| #[repr(C)] | ||
| #[derive(Debug, Copy, Clone)] | ||
| #[allow(missing_docs)] | ||
| pub struct MountAttr<'a> { |
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 struct should be non_exhaustive.
Preliminary implementation of
mount_setattr.A few notes:
sizenon-exported. Should we export this?mount_setattrinmisc.rsbecause I am going to add statmount and listmount syscall once 6.8 releases andlibcadds the syscall number.Fix #975