device_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::asynchronous::BlockAsync;
19use crate::DiskOption;
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        // To probe write support without clobbering existing disk data, read the byte
37        // at offset 0 first and write it back.
38        if preadv2(borrowed_fd, &mut iovs, 0, 0) != 1 {
39            return false;
40        }
41        pwritev2(
42            borrowed_fd,
43            IoBufMut::as_iobufs(&iovs),
44            0,
45            libc::RWF_DONTCACHE,
46        )
47    } else {
48        preadv2(borrowed_fd, &mut iovs, 0, libc::RWF_DONTCACHE)
49    };
50    if res < 0 {
51        let err = base::Error::last();
52        match err.errno() {
53            libc::EOPNOTSUPP | libc::EINVAL | libc::ENOSYS => false,
54            _ => {
55                base::warn!("Unexpected error checking for DONTCACHE support: {err}");
56                false
57            }
58        }
59    } else {
60        true
61    }
62}
63
64impl DiskOption {
65    /// Open the specified disk file.
66    pub fn open(&self) -> anyhow::Result<Box<dyn DiskFile>> {
67        disk::open_disk_file(disk::DiskFileParams {
68            path: self.path.clone(),
69            is_read_only: self.read_only,
70            is_sparse_file: self.sparse,
71            is_direct: self.direct,
72            lock: self.lock,
73            ..Default::default()
74        })
75        .context("open_disk_file failed")
76    }
77}
78
79impl BlockAsync {
80    pub fn create_executor(&self) -> Executor {
81        Executor::with_executor_kind(self.executor_kind).expect("Failed to create an executor")
82    }
83}