devices/virtio/block/sys/
linux.rs

1// Copyright 2022 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::cmp::max;
6use std::cmp::min;
7use std::os::fd::BorrowedFd;
8
9use anyhow::Context;
10use base::linux::preadv2;
11use base::linux::pwritev2;
12use base::unix::iov_max;
13use base::IoBufMut;
14use base::RawDescriptor;
15use cros_async::Executor;
16use disk::DiskFile;
17
18use crate::virtio::block::DiskOption;
19use crate::virtio::BlockAsync;
20
21pub fn get_seg_max(queue_size: u16) -> u32 {
22    let seg_max = min(max(iov_max(), 1), u32::MAX as usize) as u32;
23
24    // Since we do not currently support indirect descriptors, the maximum
25    // number of segments must be smaller than the queue size.
26    // In addition, the request header and status each consume a descriptor.
27    min(seg_max, u32::from(queue_size) - 2)
28}
29
30pub fn check_dontcache_support(fd: RawDescriptor, write: bool) -> bool {
31    let mut buf = [0u8; 1];
32    let mut iovs = [IoBufMut::new(&mut buf)];
33    // SAFETY: fd is an open file descriptor.
34    let borrowed_fd = unsafe { BorrowedFd::borrow_raw(fd) };
35    let res = if write {
36        pwritev2(
37            borrowed_fd,
38            IoBufMut::as_iobufs(&iovs),
39            0,
40            libc::RWF_DONTCACHE,
41        )
42    } else {
43        preadv2(borrowed_fd, &mut iovs, 0, libc::RWF_DONTCACHE)
44    };
45    if res < 0 {
46        let err = base::Error::last();
47        match err.errno() {
48            libc::EOPNOTSUPP | libc::EINVAL | libc::ENOSYS => false,
49            _ => {
50                base::warn!("Unexpected error checking for DONTCACHE support: {err}");
51                false
52            }
53        }
54    } else {
55        true
56    }
57}
58
59impl DiskOption {
60    /// Open the specified disk file.
61    pub fn open(&self) -> anyhow::Result<Box<dyn DiskFile>> {
62        disk::open_disk_file(disk::DiskFileParams {
63            path: self.path.clone(),
64            is_read_only: self.read_only,
65            is_sparse_file: self.sparse,
66            is_direct: self.direct,
67            lock: self.lock,
68            ..Default::default()
69        })
70        .context("open_disk_file failed")
71    }
72}
73
74impl BlockAsync {
75    pub fn create_executor(&self) -> Executor {
76        Executor::with_executor_kind(self.executor_kind).expect("Failed to create an executor")
77    }
78}