Re: [RFC PATCH 06/19] rust: fs: introduce `FileSystem::init_root`

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, Oct 21, 2023 at 01:48:28PM +0000, Benno Lossin wrote:
> On 20.10.23 02:52, Boqun Feng wrote:
> > On Thu, Oct 19, 2023 at 02:30:56PM +0000, Benno Lossin wrote:
> > [...]
> >>> +        let inode =
> >>> +            ptr::NonNull::new(unsafe { bindings::iget_locked(self.0.get(), ino) }).ok_or(ENOMEM)?;
> >>> +
> >>> +        // SAFETY: `inode` is valid for read, but there could be concurrent writers (e.g., if it's
> >>> +        // an already-initialised inode), so we use `read_volatile` to read its current state.
> >>> +        let state = unsafe { ptr::read_volatile(ptr::addr_of!((*inode.as_ptr()).i_state)) };
> >>
> >> Are you sure that `read_volatile` is sufficient for this use case? The
> >> documentation [1] clearly states that concurrent write operations are still
> >> UB:
> >>
> >>      Just like in C, whether an operation is volatile has no bearing
> >>      whatsoever on questions involving concurrent access from multiple
> >>      threads. Volatile accesses behave exactly like non-atomic accesses in
> >>      that regard. In particular, a race between a read_volatile and any
> >>      write operation to the same location is undefined behavior.
> >>
> > 
> > Right, `read_volatile` can have data race. I think what we can do here
> > is:
> > 
> > 	// SAFETY: `i_state` in `inode` is `unsigned long`, therefore
> > 	// it's safe to treat it as `AtomicUsize` and do a relaxed read.
> > 	let state = unsafe { *(ptr::addr_of!((*inode.as_ptr()).i_state).cast::<AtomicUsize>()).load(Relaxed) };
> 
> I am not sure if that is enough. What kind of writes happen
> concurrently on the C side? If they are atomic, then this should
> be fine, if they are not synchronized at all, then it could be
> problematic, as miri says that it is still UB:
> https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=aa75fb6805c8d67ade8837531a2096d0
> 

You're not wrong, my suggestion here had the assumption that write part
of ->i_state is atomic (I hadn't look into that). Now a quick look tells
it isn't, for example in fs/f2fs/namei.c, there is:

	inode->i_state |= I_LINKABLE;

so I think we need to take the inode->i_lock here for a data-race free
solution. Or if we have something like:

	https://github.com/rust-lang/unsafe-code-guidelines/issues/321

in Rust.

Benno, notice my reasoning about whether a write is atomic is less
strict, since in C side, in the current rule of the kernel, plain
writes to machine words can be treated as atomic, in case you're
interested CONFIG_KCSAN_ASSUME_PLAIN_WRITES_ATOMIC is the pointer ;-)

While we are at it, adding Marco, could kcsan work for Rust code? If I
understand correctly, as long as Rust compilers could generate these
__tsan_* instrument functions, it should work, right?

Regards,
Boqun

> -- 
> Cheers,
> Benno




[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [NTFS 3]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [NTFS 3]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux