qcow2_rs/
uring.rs

1use crate::error::Qcow2Result;
2use crate::helpers::slice_to_vec;
3use crate::ops::*;
4#[rustversion::before(1.75)]
5use async_trait::async_trait;
6use nix::fcntl::{fallocate, FallocateFlags};
7use std::os::unix::io::AsRawFd;
8use std::path::Path;
9use tokio_uring::fs::{File, OpenOptions};
10
11#[derive(Debug)]
12pub struct Qcow2IoUring {
13    file: File,
14}
15
16impl Qcow2IoUring {
17    pub async fn new(path: &Path, ro: bool, dio: bool) -> Qcow2IoUring {
18        let file = OpenOptions::new()
19            .read(true)
20            .write(!ro)
21            .open(path.to_path_buf())
22            .await
23            .unwrap();
24
25        if dio {
26            unsafe {
27                libc::fcntl(file.as_raw_fd(), libc::F_SETFL, libc::O_DIRECT);
28            }
29        }
30        Qcow2IoUring { file }
31    }
32}
33
34#[rustversion::attr(before(1.75), async_trait(?Send))]
35impl Qcow2IoOps for Qcow2IoUring {
36    async fn read_to(&self, offset: u64, buf: &mut [u8]) -> Qcow2Result<usize> {
37        let ubuf = slice_to_vec::<u8>(buf);
38        let (res, ubuf) = self.file.read_at(ubuf, offset).await;
39
40        std::mem::forget(ubuf);
41        match res {
42            Err(_) => Err("tokio-uring read failed".into()),
43            Ok(r) => Ok(r),
44        }
45    }
46
47    async fn write_from(&self, offset: u64, buf: &[u8]) -> Qcow2Result<()> {
48        let ubuf = slice_to_vec::<u8>(buf);
49
50        //let (res, ubuf) = self.file.write_at(ubuf, offset).submit().await; //tokio-uring github
51        let (res, ubuf) = self.file.write_at(ubuf, offset).await;
52
53        std::mem::forget(ubuf);
54        match res {
55            Err(_) => Err("tokio-uring write failed".into()),
56            Ok(_) => Ok(()),
57        }
58    }
59
60    async fn fallocate(&self, offset: u64, len: usize, flags: u32) -> Qcow2Result<()> {
61        // tokio-uring github fallocate
62        /*
63        let res = self
64            .file
65            .fallocate(offset, len.try_into().unwrap(), flags)
66            .await;
67        match res {
68            Err(_) => Err("tokio-uring fallocate failed".into()),
69            Ok(_) => Ok(()),
70        }*/
71
72        // the latest tokio-uring crate(0.4) doesn't support fallocate yet, so use
73        // sync nix fallocate() syscall
74        let f = if (flags & Qcow2OpsFlags::FALLOCATE_ZERO_RAGE) != 0 {
75            FallocateFlags::FALLOC_FL_PUNCH_HOLE | FallocateFlags::FALLOC_FL_ZERO_RANGE
76        } else {
77            FallocateFlags::FALLOC_FL_PUNCH_HOLE
78        };
79
80        Ok(fallocate(
81            self.file.as_raw_fd(),
82            f,
83            offset as libc::off_t,
84            len as libc::off_t,
85        )?)
86    }
87
88    async fn fsync(&self, _offset: u64, _len: usize, _flags: u32) -> Qcow2Result<()> {
89        self.file.sync_all().await?;
90        Ok(())
91    }
92}