-
Notifications
You must be signed in to change notification settings - Fork 448
Add an abstraction over device' fwnode #925
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: rust
Are you sure you want to change the base?
Conversation
41e17c9
to
cf5a983
Compare
rust/kernel/fwnode.rs
Outdated
/// | ||
/// The pointer is valid. | ||
pub struct Node { | ||
pub(crate) ptr: *mut bindings::fwnode_handle, |
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 this should store UnsafeCell<bindings::fwnode_handle>
and be #[repr(transparent)]
directly and implement AlwaysRefCounted
. Then you can return an ARef<Node>
from NodeIterator
. See for example
Lines 113 to 179 in 729c030
#[repr(transparent)] | |
pub struct File(pub(crate) UnsafeCell<bindings::file>); | |
// TODO: Accessing fields of `struct file` through the pointer is UB because other threads may be | |
// writing to them. However, this is how the C code currently operates: naked reads and writes to | |
// fields. Even if we used relaxed atomics on the Rust side, we can't force this on the C side. | |
impl File { | |
/// Constructs a new [`struct file`] wrapper from a file descriptor. | |
/// | |
/// The file descriptor belongs to the current process. | |
pub fn from_fd(fd: u32) -> Result<ARef<Self>> { | |
// SAFETY: FFI call, there are no requirements on `fd`. | |
let ptr = ptr::NonNull::new(unsafe { bindings::fget(fd) }).ok_or(EBADF)?; | |
// SAFETY: `fget` increments the refcount before returning. | |
Ok(unsafe { ARef::from_raw(ptr.cast()) }) | |
} | |
/// Creates a reference to a [`File`] from a valid pointer. | |
/// | |
/// # Safety | |
/// | |
/// The caller must ensure that `ptr` is valid and remains valid for the lifetime of the | |
/// returned [`File`] instance. | |
pub(crate) unsafe fn from_ptr<'a>(ptr: *const bindings::file) -> &'a File { | |
// SAFETY: The safety requirements guarantee the validity of the dereference, while the | |
// `File` type being transparent makes the cast ok. | |
unsafe { &*ptr.cast() } | |
} | |
/// Returns the current seek/cursor/pointer position (`struct file::f_pos`). | |
pub fn pos(&self) -> u64 { | |
// SAFETY: The file is valid because the shared reference guarantees a nonzero refcount. | |
unsafe { core::ptr::addr_of!((*self.0.get()).f_pos).read() as _ } | |
} | |
/// Returns the credentials of the task that originally opened the file. | |
pub fn cred(&self) -> &Credential { | |
// SAFETY: The file is valid because the shared reference guarantees a nonzero refcount. | |
let ptr = unsafe { core::ptr::addr_of!((*self.0.get()).f_cred).read() }; | |
// SAFETY: The lifetimes of `self` and `Credential` are tied, so it is guaranteed that | |
// the credential pointer remains valid (because the file is still alive, and it doesn't | |
// change over the lifetime of a file). | |
unsafe { Credential::from_ptr(ptr) } | |
} | |
/// Returns the flags associated with the file. | |
/// | |
/// The flags are a combination of the constants in [`flags`]. | |
pub fn flags(&self) -> u32 { | |
// SAFETY: The file is valid because the shared reference guarantees a nonzero refcount. | |
unsafe { core::ptr::addr_of!((*self.0.get()).f_flags).read() } | |
} | |
} | |
// SAFETY: The type invariants guarantee that `File` is always ref-counted. | |
unsafe impl AlwaysRefCounted for File { | |
fn inc_ref(&self) { | |
// SAFETY: The existence of a shared reference means that the refcount is nonzero. | |
unsafe { bindings::get_file(self.0.get()) }; | |
} | |
unsafe fn dec_ref(obj: ptr::NonNull<Self>) { | |
// SAFETY: The safety requirements guarantee that the refcount is nonzero. | |
unsafe { bindings::fput(obj.cast().as_ptr()) } | |
} | |
} |
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.
thanks @bjorn3 for the review! Is it correct to reason that this is not required for DeviceNode since it's ptr is not public? And hence its safe to rely on rust's reference counting completely.
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.
fwnode_handle
is reference counted too, so DeviceNode
should probably do the same. Also dev_fwnode
seems to return a pointer without incrementing reference count. As such I think DeviceNode::from
should return &'a DeviceNode
where 'a
is the lifetime of the device.
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.
Also I don't know if you endpoints of nodes can have endpoints themself, but if so maybe DeviceNode
should be merged into Node
.
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.
if you endpoints of nodes can have endpoints themself,
I took your recommendation and merged DeviceNode
and Node
. Based on the documentation endpoints should not have endpoints themselves. However, calling endpoints()
returns an Iterator which may be empty as well, so should be safe for consumption.
dev_fwnode seems to return a pointer without incrementing reference count.
I have added a fwnode_handle_get
call to ensure that the refcount is incremented before passing it to the ARef. Since I am explicitly incrementing the refcount in Node::from
I am not associating the lifetime of Node
with the device. Am i missing anything?
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.
dev_fwnode seems to return a pointer without incrementing reference count.
I have added a
fwnode_handle_get
call to ensure that the refcount is incremented before passing it to the ARef. Since I am explicitly incrementing the refcount inNode::from
I am not associating the lifetime ofNode
with the device. Am i missing anything?
Should be fine now.
c465f21
to
d669a10
Compare
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.
Based on what I know about this interface, it looks good. I'm not sure if Node
should be called this or something closer to fwnode_handle
though like FwNodeHandle
.
rust/kernel/fwnode.rs
Outdated
} | ||
} | ||
|
||
/// Implements the Iterator trait to iterate the device's endpoints given the `DeviceNode` |
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.
Here and elsewhere there are still references to DeviceNode.
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.
My bad! I have fixed them now.
d669a10
to
0b6ace3
Compare
Added abstraction APIs for accessing device's fwnode. Signed-off-by: Vinay Varma <vin1990@gmail.com>
0b6ace3
to
840d092
Compare
Since the module name is called I have also added two methods |
I was conflicted about naming the module
fwnode
when the functions it implements are fromlinux/property.h
, yet i feelfwnode
provides more clarity about what the module provides. I have (currently) implemented only theendpoints
method which provides a rust interface to traversing the tree. There were no changes required inbinding_helper.rs
sincelinux/property.h
is already included in some of the other headers included.