On Wed, Oct 18, 2023 at 09:25:05AM -0300, Wedson Almeida Filho wrote: [...] > +/// An inode that is locked and hasn't been initialised yet. > +#[repr(transparent)] > +pub struct NewINode<T: FileSystem + ?Sized>(ARef<INode<T>>); > + > +impl<T: FileSystem + ?Sized> NewINode<T> { > + /// Initialises the new inode with the given parameters. > + pub fn init(self, params: INodeParams) -> Result<ARef<INode<T>>> { > + // SAFETY: This is a new inode, so it's safe to manipulate it mutably. > + let inode = unsafe { &mut *self.0 .0.get() }; > + > + let mode = match params.typ { > + INodeType::Dir => { > + // SAFETY: `simple_dir_operations` never changes, it's safe to reference it. > + inode.__bindgen_anon_3.i_fop = unsafe { &bindings::simple_dir_operations }; > + > + // SAFETY: `simple_dir_inode_operations` never changes, it's safe to reference it. > + inode.i_op = unsafe { &bindings::simple_dir_inode_operations }; > + bindings::S_IFDIR > + } > + }; > + > + inode.i_mode = (params.mode & 0o777) | u16::try_from(mode)?; > + inode.i_size = params.size; > + inode.i_blocks = params.blocks; > + > + inode.__i_ctime = params.ctime.into(); > + inode.i_mtime = params.mtime.into(); > + inode.i_atime = params.atime.into(); > + > + // SAFETY: inode is a new inode, so it is valid for write. > + unsafe { > + bindings::set_nlink(inode, params.nlink); > + bindings::i_uid_write(inode, params.uid); > + bindings::i_gid_write(inode, params.gid); > + bindings::unlock_new_inode(inode); > + } > + > + // SAFETY: We are manually destructuring `self` and preventing `drop` from being called. > + Ok(unsafe { (&ManuallyDrop::new(self).0 as *const ARef<INode<T>>).read() }) How do we feel about using transmute here? ;-) I.e. // SAFETY: `NewINode` is transparent to `ARef<INode<_>>`, and // the inode has been initialised, so it's safety to change the // object type. Ok(unsafe { core::mem::transmute(self) }) What we actually want here is changing the type of the object (i.e. bitwise move from one type to another), seems to me that transmute is the best fit here. Thoughts? Regards, Boqun > + } > +} > + > +impl<T: FileSystem + ?Sized> Drop for NewINode<T> { > + fn drop(&mut self) { > + // SAFETY: The new inode failed to be turned into an initialised inode, so it's safe (and > + // in fact required) to call `iget_failed` on it. > + unsafe { bindings::iget_failed(self.0 .0.get()) }; > + } > +} > + [...]