From bbd4cd9be2a5f2c3a9acba8548380ad55455d21a Mon Sep 17 00:00:00 2001 From: LI Qing Date: Tue, 25 Feb 2020 03:00:08 +0000 Subject: [PATCH] Add fstat() and poll() for the random device --- src/libos/src/fs/dev_fs/dev_random.rs | 47 +++++++++++++++++++++++++++ src/libos/src/fs/dev_fs/mod.rs | 2 +- src/libos/src/fs/mod.rs | 1 + src/libos/src/net/io_multiplexing.rs | 4 ++- test/device/main.c | 43 ++++++++++++++++++++++++ 5 files changed, 95 insertions(+), 2 deletions(-) diff --git a/src/libos/src/fs/dev_fs/dev_random.rs b/src/libos/src/fs/dev_fs/dev_random.rs index ca37beb9..f37a67b5 100644 --- a/src/libos/src/fs/dev_fs/dev_random.rs +++ b/src/libos/src/fs/dev_fs/dev_random.rs @@ -41,7 +41,54 @@ impl File for DevRandom { Ok(total_nbytes) } + fn metadata(&self) -> Result { + Ok(Metadata { + dev: 0, + inode: 0, + size: 0, + blk_size: 0, + blocks: 0, + atime: Timespec { sec: 0, nsec: 0 }, + mtime: Timespec { sec: 0, nsec: 0 }, + ctime: Timespec { sec: 0, nsec: 0 }, + type_: FileType::CharDevice, + mode: 0444, + nlinks: 0, + uid: 0, + gid: 0, + rdev: 0, + }) + } + fn as_any(&self) -> &dyn Any { self } } + +impl DevRandom { + pub fn poll(&self, fd: &mut libc::pollfd) -> Result { + // Just support POLLIN event, because the device is read-only currently + let (num, revents_option) = if (fd.events & libc::POLLIN) != 0 { + (1, Some(libc::POLLIN)) + } else { + // Device is not ready + (0, None) + }; + if let Some(revents) = revents_option { + fd.revents = revents; + } + Ok(num) + } +} + +pub trait AsDevRandom { + fn as_dev_random(&self) -> Result<&DevRandom>; +} + +impl AsDevRandom for FileRef { + fn as_dev_random(&self) -> Result<&DevRandom> { + self.as_any() + .downcast_ref::() + .ok_or_else(|| errno!(EBADF, "not random device")) + } +} diff --git a/src/libos/src/fs/dev_fs/mod.rs b/src/libos/src/fs/dev_fs/mod.rs index af1695dc..8ef85bb7 100644 --- a/src/libos/src/fs/dev_fs/mod.rs +++ b/src/libos/src/fs/dev_fs/mod.rs @@ -1,7 +1,7 @@ use super::*; pub use self::dev_null::DevNull; -pub use self::dev_random::DevRandom; +pub use self::dev_random::{AsDevRandom, DevRandom}; pub use self::dev_sgx::DevSgx; pub use self::dev_zero::DevZero; diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index c509d49b..88e64d17 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -8,6 +8,7 @@ use std::fmt; use std::io::{Read, Seek, SeekFrom, Write}; use std::mem::MaybeUninit; +pub use self::dev_fs::AsDevRandom; pub use self::file::{File, FileRef}; pub use self::file_ops::{AccessMode, CreationFlags, Stat, StatusFlags}; pub use self::file_ops::{Flock, FlockType}; diff --git a/src/libos/src/net/io_multiplexing.rs b/src/libos/src/net/io_multiplexing.rs index 7d6539b7..6530a1c1 100644 --- a/src/libos/src/net/io_multiplexing.rs +++ b/src/libos/src/net/io_multiplexing.rs @@ -1,5 +1,5 @@ use super::*; -use fs::{File, FileDesc, FileRef}; +use fs::{AsDevRandom, File, FileDesc, FileRef}; use std::any::Any; use std::collections::btree_map::BTreeMap; use std::fmt; @@ -143,6 +143,8 @@ pub fn do_poll(polls: &mut [libc::pollfd], timeout: c_int) -> Result { poll.revents &= poll.events; warn!("poll unix socket is unimplemented, spin for read"); return Ok(1); + } else if let Ok(dev_random) = file_ref.as_dev_random() { + return Ok(dev_random.poll(poll)?); } else { return_errno!(EBADF, "not a socket"); } diff --git a/test/device/main.c b/test/device/main.c index 8d767709..f3933a1c 100644 --- a/test/device/main.c +++ b/test/device/main.c @@ -1,4 +1,7 @@ +#include +#include #include +#include #include #include #include "test.h" @@ -67,6 +70,44 @@ int test_dev_urandom() { return 0; } +int test_dev_urandom_fstat() { + int fd; + struct stat stat_buf; + + if ((fd = open("/dev/urandom", O_RDONLY)) < 0) { + THROW_ERROR("failed to open the file"); + } + if (fstat(fd, &stat_buf) < 0) { + close(fd); + THROW_ERROR("failed to fstat the file"); + } + close(fd); + if ((stat_buf.st_mode & S_IFMT) != S_IFCHR) { + THROW_ERROR("not a character device"); + } + return 0; +} + +int test_dev_urandom_poll() { + int fd; + struct pollfd fds; + + if ((fd = open("/dev/urandom", O_RDONLY)) < 0) { + THROW_ERROR("failed to open the file"); + } + fds.fd = fd; + fds.events = POLLIN; + if (poll(&fds, 1, 5) <= 0) { + close(fd); + THROW_ERROR("failed to poll or file is not ready"); + } + close(fd); + if (fds.revents != POLLIN) { + THROW_ERROR("not expected returned events"); + } + return 0; +} + int test_dev_arandom() { if (check_file_readable("/dev/arandom")) { THROW_ERROR("failed to read from /dev/arandom"); @@ -83,6 +124,8 @@ static test_case_t test_cases[] = { TEST_CASE(test_dev_zero), TEST_CASE(test_dev_random), TEST_CASE(test_dev_urandom), + TEST_CASE(test_dev_urandom_fstat), + TEST_CASE(test_dev_urandom_poll), TEST_CASE(test_dev_arandom), };