-
Notifications
You must be signed in to change notification settings - Fork 191
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_fd
exposed 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.
openat2
has a future extensibility struct that rustix decided to inline into the function signature.clone3
has a future extensibility struct but is impossible to be implemented by rustix.mount_setattr
,sched_setattr
,landlock_create_ruleset
,statmount
/listmount
,perf_event_open
have 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:
size
non-exported. Should we export this?mount_setattr
inmisc.rs
because I am going to add statmount and listmount syscall once 6.8 releases andlibc
adds the syscall number.Fix #975