diff --git a/drivers/staging/android/ashmem_rust.rs b/drivers/staging/android/ashmem_rust.rs index d25e2a33301d..21829e9c2043 100644 --- a/drivers/staging/android/ashmem_rust.rs +++ b/drivers/staging/android/ashmem_rust.rs @@ -16,7 +16,7 @@ use kernel::{ error::Result, fs::File, ioctl::_IOC_SIZE, - miscdevice::{MiscDevice, MiscDeviceOptions, MiscDeviceRegistration}, + miscdevice::{IovIter, Kiocb, MiscDevice, MiscDeviceOptions, MiscDeviceRegistration}, mm::virt::{flags as vma_flags, VmAreaNew}, page::page_align, prelude::*, @@ -155,6 +155,29 @@ impl MiscDevice for Ashmem { Ok(()) } + fn read_iter(mut kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIter) -> Result { + let me = kiocb.private_data(); + let asma_file = { + let asma = me.inner.lock(); + if asma.size == 0 { + // If size is not set, or set to 0, always return EOF. + return Ok(0); + } + match asma.file.as_ref() { + Some(asma_file) => asma_file.clone(), + None => return Err(EBADF), + } + }; + + let ret = asma_file.vfs_iter_read(iov, kiocb.ki_pos_mut())?; + + // SAFETY: We protect the shmem file with the same mechanism as the ashmem file. We are in + // read_iter, so our caller ensures that accessing f_pos is okay. + unsafe { shmem::file_set_fpos(asma_file.file(), kiocb.ki_pos()) }; + + Ok(ret as usize) + } + fn ioctl(me: Pin<&Ashmem>, _file: &File, cmd: u32, arg: usize) -> Result { let size = _IOC_SIZE(cmd); match cmd { diff --git a/drivers/staging/android/shmem.rs b/drivers/staging/android/shmem.rs index 1fe15e390093..0c545ae78e5f 100644 --- a/drivers/staging/android/shmem.rs +++ b/drivers/staging/android/shmem.rs @@ -7,7 +7,8 @@ use kernel::{ bindings, error::{from_err_ptr, to_result, Result}, - fs::file::File, + fs::file::{File, LocalFile}, + miscdevice::{loff_t, IovIter}, mm::virt::{vm_flags_t, VmAreaNew}, prelude::*, str::CStr, @@ -20,6 +21,14 @@ use core::{ ptr::{addr_of_mut, NonNull}, }; +/// # Safety +/// +/// Caller must ensure that access to the file position is properly synchronized. +pub(crate) unsafe fn file_set_fpos(file: &LocalFile, pos: loff_t) { + // SAFETY: Caller ensures that this is okay. + unsafe { (*file.as_ptr()).f_pos = pos }; +} + pub(crate) fn vma_set_anonymous(vma: &VmAreaNew) { // SAFETY: The `VmAreaNew` type is only used when the vma is being set up, so this operation is // safe. @@ -68,6 +77,17 @@ impl ShmemFile { pub(crate) fn file(&self) -> &File { &self.inner } + + pub(crate) fn vfs_iter_read(&self, iov: &mut IovIter, pos: &mut loff_t) -> Result { + // SAFETY: Just an FFI call. The file and iov is valid. + let ret = unsafe { bindings::vfs_iter_read(self.inner.as_ptr(), iov.as_raw(), pos, 0) }; + + if ret < 0 { + Err(Error::from_errno(ret as i32)) + } else { + Ok(ret as loff_t) + } + } } /// Fix the lockdep class of the shmem inode.