devices: block: track flush timer armed state

Rather than querying the flush timerfd state repeatedly on every write,
just track the state in a variable.  This avoids an extra
timerfd_gettime() syscall on every write.

BUG=None
TEST=Verify that the flush timer still fires via strace

Change-Id: I5437d26570de466f05b496d3e0dce08a521c4fde
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1247443
Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
Daniel Verkamp 2018-09-26 17:49:57 -07:00 committed by chrome-bot
parent 46f70e8c16
commit b605850bce

View file

@ -174,7 +174,6 @@ fn discard_write_zeroes_segment(
#[derive(Debug)] #[derive(Debug)]
enum ExecuteError { enum ExecuteError {
/// Error arming the flush timer. /// Error arming the flush timer.
ArmingTimer(SysError),
Flush(io::Error), Flush(io::Error),
Read { Read {
addr: GuestAddress, addr: GuestAddress,
@ -208,7 +207,6 @@ enum ExecuteError {
impl ExecuteError { impl ExecuteError {
fn status(&self) -> u8 { fn status(&self) -> u8 {
match self { match self {
&ExecuteError::ArmingTimer(_) => VIRTIO_BLK_S_IOERR,
&ExecuteError::Flush(_) => VIRTIO_BLK_S_IOERR, &ExecuteError::Flush(_) => VIRTIO_BLK_S_IOERR,
&ExecuteError::Read{ .. } => VIRTIO_BLK_S_IOERR, &ExecuteError::Read{ .. } => VIRTIO_BLK_S_IOERR,
&ExecuteError::Seek{ .. } => VIRTIO_BLK_S_IOERR, &ExecuteError::Seek{ .. } => VIRTIO_BLK_S_IOERR,
@ -366,6 +364,7 @@ impl Request {
read_only: bool, read_only: bool,
disk: &mut T, disk: &mut T,
flush_timer: &mut TimerFd, flush_timer: &mut TimerFd,
flush_timer_armed: &mut bool,
mem: &GuestMemory, mem: &GuestMemory,
) -> result::Result<u32, ExecuteError> { ) -> result::Result<u32, ExecuteError> {
// Delay after a write when the file is auto-flushed. // Delay after a write when the file is auto-flushed.
@ -396,10 +395,11 @@ impl Request {
sector: self.sector, sector: self.sector,
guestmemerr: e, guestmemerr: e,
})?; })?;
if !flush_timer.is_armed().map_err(ExecuteError::ArmingTimer)? { if !*flush_timer_armed {
flush_timer flush_timer
.reset(flush_delay, None) .reset(flush_delay, None)
.map_err(ExecuteError::TimerFd)?; .map_err(ExecuteError::TimerFd)?;
*flush_timer_armed = true;
} }
} }
RequestType::Discard | RequestType::WriteZeroes => { RequestType::Discard | RequestType::WriteZeroes => {
@ -437,6 +437,7 @@ impl Request {
RequestType::Flush => { RequestType::Flush => {
disk.flush().map_err(ExecuteError::Flush)?; disk.flush().map_err(ExecuteError::Flush)?;
flush_timer.clear().map_err(ExecuteError::TimerFd)?; flush_timer.clear().map_err(ExecuteError::TimerFd)?;
*flush_timer_armed = false;
} }
RequestType::Unsupported(t) => return Err(ExecuteError::Unsupported(t)), RequestType::Unsupported(t) => return Err(ExecuteError::Unsupported(t)),
}; };
@ -454,7 +455,12 @@ struct Worker<T: DiskFile> {
} }
impl<T: DiskFile> Worker<T> { impl<T: DiskFile> Worker<T> {
fn process_queue(&mut self, queue_index: usize, flush_timer: &mut TimerFd) -> bool { fn process_queue(
&mut self,
queue_index: usize,
flush_timer: &mut TimerFd,
flush_timer_armed: &mut bool,
) -> bool {
let queue = &mut self.queues[queue_index]; let queue = &mut self.queues[queue_index];
let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize]; let mut used_desc_heads = [(0, 0); QUEUE_SIZE as usize];
@ -467,6 +473,7 @@ impl<T: DiskFile> Worker<T> {
self.read_only, self.read_only,
&mut self.disk_image, &mut self.disk_image,
flush_timer, flush_timer,
flush_timer_armed,
&self.mem, &self.mem,
) { ) {
Ok(l) => { Ok(l) => {
@ -521,6 +528,7 @@ impl<T: DiskFile> Worker<T> {
return; return;
} }
}; };
let mut flush_timer_armed = false;
let poll_ctx: PollContext<Token> = let poll_ctx: PollContext<Token> =
match PollContext::new() match PollContext::new()
@ -561,7 +569,8 @@ impl<T: DiskFile> Worker<T> {
error!("failed reading queue EventFd: {:?}", e); error!("failed reading queue EventFd: {:?}", e);
break 'poll; break 'poll;
} }
needs_interrupt |= self.process_queue(0, &mut flush_timer); needs_interrupt |=
self.process_queue(0, &mut flush_timer, &mut flush_timer_armed);
} }
Token::Kill => break 'poll, Token::Kill => break 'poll,
} }