diff options
author | Zach Reizner <zachr@google.com> | 2017-08-02 15:02:28 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-08-03 01:11:01 -0700 |
commit | 7a9de27c36b9a5ea3e29b3508939c20e6a5c7779 (patch) | |
tree | a644cef688f79436b576e44bd9592c64fbc54972 /sys_util/src/sock_ctrl_msg.rs | |
parent | 3eddedd005c0333390e1eae4c2f0eb661790748e (diff) | |
download | crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar.gz crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar.bz2 crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar.lz crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar.xz crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.tar.zst crosvm-7a9de27c36b9a5ea3e29b3508939c20e6a5c7779.zip |
sys_util: allow sock_ctrl_msg to be more flexible with iovecs
Because there are more than one kind of slice (typical &[T] and VolatileSlice), the trait IntoIovec is added that any linear memory region-like type can implement. This helps to reduce the number of copies needed when dealing with volatile memory. TEST=cargo test BUG=chromium:738638 Change-Id: I86bbb693cb7a10ec85bafccf562c078167121c03 Reviewed-on: https://chromium-review.googlesource.com/599042 Commit-Ready: Zach Reizner <zachr@chromium.org> Tested-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'sys_util/src/sock_ctrl_msg.rs')
-rw-r--r-- | sys_util/src/sock_ctrl_msg.rs | 60 |
1 files changed, 49 insertions, 11 deletions
diff --git a/sys_util/src/sock_ctrl_msg.rs b/sys_util/src/sock_ctrl_msg.rs index ddbfef8..2d4b91c 100644 --- a/sys_util/src/sock_ctrl_msg.rs +++ b/sys_util/src/sock_ctrl_msg.rs @@ -6,7 +6,9 @@ use std::fs::File; use std::os::unix::io::{AsRawFd, RawFd, FromRawFd}; use std::os::unix::net::{UnixDatagram, UnixStream}; -use libc::{iovec, c_void}; +use libc::{c_void, iovec}; + +use data_model::VolatileSlice; use {Result, Error}; @@ -56,6 +58,43 @@ impl ScmSocket for UnixStream { } } +/// Trait for types that can be converted into an `iovec` that can be referenced by a syscall for +/// the lifetime of this object. +/// +/// This trait is unsafe because interfaces that use this trait depend on the base pointer and size +/// being accurate. +pub unsafe trait IntoIovec { + /// Gets the base pointer of this `iovec`. + fn as_ptr(&self) -> *const c_void; + + /// Gets the size in bytes of this `iovec`. + fn size(&self) -> usize; +} + +// Safe because this slice can not have another mutable reference and it's pointer and size are +// guaranteed to be valid. +unsafe impl<'a> IntoIovec for &'a [u8] { + fn as_ptr(&self) -> *const c_void { + self.as_ref().as_ptr() as *const c_void + } + + fn size(&self) -> usize { + self.len() + } +} + +// Safe because volatile slices are only ever accessed with other volatile interfaces and the +// pointer and size are guaranteed to be accurate. +unsafe impl<'a> IntoIovec for VolatileSlice<'a> { + fn as_ptr(&self) -> *const c_void { + self.as_ptr() as *const c_void + } + + fn size(&self) -> usize { + self.size() + } +} + /// Used to send and receive messages with file descriptors on sockets that accept control messages /// (e.g. Unix domain sockets). pub struct Scm { @@ -85,23 +124,22 @@ impl Scm { /// # Arguments /// /// * `socket` - A socket that supports socket control messages. - /// * `bufs` - A list of buffers to send on the `socket`. These will not be copied before - /// `sendmsg` is called. + /// * `bufs` - A list of buffers to send on the `socket`. /// * `fds` - A list of file descriptors to be sent. - pub fn send<T: ScmSocket>(&mut self, + pub fn send<T: ScmSocket, D: IntoIovec>(&mut self, socket: &T, - bufs: &[&[u8]], + bufs: &[D], fds: &[RawFd]) -> Result<usize> { let cmsg_buf_len = cmsg_buffer_len(fds.len()); self.cmsg_buffer.reserve(cmsg_buf_len); self.vecs.clear(); - for buf in bufs { + for ref buf in bufs { self.vecs .push(iovec { - iov_base: buf.as_ptr() as *mut c_void, - iov_len: buf.len(), - }); + iov_base: buf.as_ptr() as *mut c_void, + iov_len: buf.size(), + }); } let write_count = unsafe { // Safe because we are giving scm_sendmsg only valid pointers and lengths and we check @@ -241,7 +279,7 @@ mod tests { let mut scm = Scm::new(1); let evt = EventFd::new().expect("failed to create eventfd"); - let write_count = scm.send(&s1, &[&[]], &[evt.as_raw_fd()]) + let write_count = scm.send(&s1, &[[].as_ref()], &[evt.as_raw_fd()]) .expect("failed to send fd"); assert_eq!(write_count, 0); @@ -270,7 +308,7 @@ mod tests { let mut scm = Scm::new(1); let evt = EventFd::new().expect("failed to create eventfd"); - let write_count = scm.send(&s1, &[&[237]], &[evt.as_raw_fd()]) + let write_count = scm.send(&s1, &[[237].as_ref()], &[evt.as_raw_fd()]) .expect("failed to send fd"); assert_eq!(write_count, 1); |