-
Notifications
You must be signed in to change notification settings - Fork 167
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
Add mount_setattr
#1002
base: main
Are you sure you want to change the base?
Add mount_setattr
#1002
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
use crate::backend::c; | ||
use crate::fd::BorrowedFd; | ||
use bitflags::bitflags; | ||
|
||
bitflags! { | ||
|
@@ -147,9 +148,10 @@ pub(crate) enum FsConfigCmd { | |
|
||
#[cfg(feature = "mount")] | ||
bitflags! { | ||
/// `MOUNT_ATTR_*` constants for use with [`fsmount`]. | ||
/// `MOUNT_ATTR_*` constants for use with [`fsmount`, `mount_setattr`]. | ||
/// | ||
/// [`fsmount`]: crate::mount::fsmount | ||
/// [`mount_setattr`]: crate::mount::mount_setattr | ||
#[repr(transparent)] | ||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] | ||
pub struct MountAttrFlags: c::c_uint { | ||
|
@@ -330,3 +332,13 @@ bitflags! { | |
|
||
#[repr(transparent)] | ||
pub(crate) struct MountFlagsArg(pub(crate) c::c_uint); | ||
|
||
#[repr(C)] | ||
#[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 commentThe reason will be displayed to describe this comment to others. Learn more. According to Linux's documentation, |
||
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 commentThe reason will be displayed to describe this comment to others. Learn more.
#[repr(C)]
pub(crate) struct mount_attr {
pub attr_set: u64,
pub attr_clr: u64,
pub propagation: u64,
pub userns_fd: u64,
} Also, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that the way 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 I can implement the changes if needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How is 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 commentThe reason will be displayed to describe this comment to others. Learn more.
It seems that it does not support setting values to
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 commentThe reason will be displayed to describe this comment to others. Learn more.
A BorrowedFd would work too. While You should first find answers to the following questions.
If a lifetime is ok, you could use a phantom. #[repr(C)]
struct mount_attr<'fd> {
attr_set: u64, // MountAttrFlags is repr(transparent) but not u64.
attr_clr: u64,
propagation: u64,
userns_fd: u64,
_userns_fd_phantom: PhantomData<BorrowedFd<'fd>>,
} Otherwise, you can also take ownership. #[repr(C)]
struct mount_attr<'fd> {
attr_set: u64, // MountAttrFlags is repr(transparent) but not u64.
attr_clr: u64,
propagation: u64,
userns_fd: u64,
_userns_fd: Option<OwnedFd>,
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I didn't consider it because it requires a change in the lifetime, but now I think it makes more sense to use I think that the main issue with For example, we could define #[repr(C)]
#[allow(non_camel_case_types)]
#[derive(Default, Debug)]
struct mount_attr {
attr_set: u64,
attr_clr: u64,
propagation: u64,
userns_fd: u64,
}
#[derive(Debug)]
pub struct MountAttr<'a> {
attr: mount_attr,
userns_fd: PhantomData<BorrowedFd<'a>>,
} Then, the default constructor would return a impl MountAttr<'static> {
pub fn new() -> Self {
MountAttr {
attr: mount_attr::default(),
userns_fd: PhantomData,
}
}
} But for impl<'a> MountAttr<'a> {
pub fn userns_fd<'b>(self, userns_fd: BorrowedFd<'b>) -> MountAttr<'b> {
MountAttr {
attr: mount_attr {
userns_fd: userns_fd.as_raw_fd() as u64,
..self.attr
},
userns_fd: PhantomData,
}
} This is important because it is inconsistent with the two ways to build an instance of // This two blocks are identical:
foo(MountAttr::new().set(MountAttrFlags::MOUNT_ATTR_FOO));
let mut attr = MountAttr::new();
attr.set(MountAttrFlags::MOUNT_ATTR_FOO);
foo(&attr);
// But these blocks are different:
foo(MountAttr::new()
.set(MountAttrFlags::MOUNT_ATTR_IDMAP)
.userns_fd(fd.as_fd()));
let mut attr = MountAttr::new();
attr.set(MountAttrFlags::MOUNT_ATTR_IDMAP); // Updates `attr`.
attr.userns_fd(fd.as_fd()); // Returns a new instance.
foo(&attr); // Call `foo()` with no `userns_fd`. Maybe, a way to avoid the possible confussion is to take the ownership of impl<'a> MountAttr<'a> {
pub fn set(mut self, flags: MountAttrFlags) -> Self {
self.attr.attr_set = flags.bits() as u64;
self
}
pub fn clear(mut self, flags: MountAttrFlags) -> Self {
self.attr.attr_clr = flags.bits() as u64;
self
}
pub fn propagation(mut self, propagation: MountPropagationFlags) -> Self {
self.attr.propagation = propagation.bits() as u64;
self
}
pub fn userns_fd<'b>(self, userns_fd: BorrowedFd<'b>) -> MountAttr<'b> {
MountAttr {
attr: mount_attr {
userns_fd: userns_fd.as_raw_fd() as u64,
..self.attr
},
userns_fd: PhantomData,
}
}
} I made a simple proof of concept with this idea. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If we add specific functions for common cases, we could add specific constructors for The I checked some projects using
I also checked other types in rustix that contain file descriptors:
To keep consistency, we could define pub struct MountAttr<'fd> {
attr: c::mount_attr,
userns_fd: PhantomData<BorrowedFd<'fd>>,
}
impl<'fd> MountAttr<'fd> {
pub fn new<Fd: AsFd>(
set: MountAttrFlags,
clear: MountAttrFlags,
propagation: MountAttrPropagation,
userns_fd: Option<&'fd Fd>,
) -> Self {
// If there is no `userns_fd`, use `fs::CWD` instead of `0`, so the
// kernel will reply with `EBADF` if `IDMAP` is set.
let userns_fd = userns_fd.map(|fd| fd.as_fd()).unwrap_or(fs::CWD);
// ...
}
pub fn new_with_idmap<Fd: AsFd>(fd: &'fd Fd) -> Self {
new(
MountAttrFlags::IDMAP,
MountAttrFlags::empty(),
MountAttrPropagation::empty(),
Some(fd),
)
}
// ...
}
impl MountAttr<'static> {
pub fn new_with_set(set: MountAttrFlags) -> Self {
new(
set,
MountAttrFlags::empty(),
MountAttrPropagation::empty(),
None,
)
}
pub fn new_with_propagation(propagation: MountAttrPropagation) -> Self {
new(
MountAttrFlags::empty(),
MountAttrFlags::empty(),
propagation,
None,
)
}
} |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
//! Miscellaneous mount APIs | ||
|
||
use crate::backend::mount::types::MountAttr; | ||
use crate::fd::BorrowedFd; | ||
use crate::fs::AtFlags; | ||
use crate::{backend, io, path}; | ||
|
||
/// `mount_setattr(dir_fd, path, flags, mount_attr)` | ||
sunfishcode marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/// | ||
/// # References | ||
/// - [Linux] | ||
/// | ||
/// [Linux]: https://man7.org/linux/man-pages/man2/mount_setattr.2.html | ||
#[inline] | ||
pub fn mount_setattr<Path: path::Arg>( | ||
dir_fd: BorrowedFd<'_>, | ||
path: Path, | ||
flags: AtFlags, | ||
mount_attr: &MountAttr<'_>, | ||
) -> io::Result<()> { | ||
path.into_with_c_str(|path| { | ||
backend::mount::syscalls::mount_setattr(dir_fd, path, flags, mount_attr) | ||
}) | ||
} |
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.