mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-22 19:32:20 +00:00
vhost_user_fs: Add support for CopyFileRange
Add support for the CopyFileRange request, introduced in FUSE 7.28. Signed-off-by: Sergio Lopez <slp@redhat.com>
This commit is contained in:
parent
b8cfdab8b6
commit
97e2d5d266
@ -1096,6 +1096,22 @@ pub trait FileSystem {
|
||||
Err(io::Error::from_raw_os_error(libc::ENOSYS))
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn copyfilerange(
|
||||
&self,
|
||||
ctx: Context,
|
||||
inode_in: Self::Inode,
|
||||
handle_in: Self::Handle,
|
||||
offset_in: u64,
|
||||
inode_out: Self::Inode,
|
||||
handle_out: Self::Handle,
|
||||
offset_out: u64,
|
||||
len: u64,
|
||||
flags: u64,
|
||||
) -> io::Result<usize> {
|
||||
Err(io::Error::from_raw_os_error(libc::ENOSYS))
|
||||
}
|
||||
|
||||
/// TODO: support this
|
||||
fn getlk(&self) -> io::Result<()> {
|
||||
Err(io::Error::from_raw_os_error(libc::ENOSYS))
|
||||
|
@ -1049,6 +1049,19 @@ pub struct LseekOut {
|
||||
}
|
||||
unsafe impl ByteValued for LseekOut {}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct CopyfilerangeIn {
|
||||
pub fh_in: u64,
|
||||
pub off_in: u64,
|
||||
pub nodeid_out: u64,
|
||||
pub fh_out: u64,
|
||||
pub off_out: u64,
|
||||
pub len: u64,
|
||||
pub flags: u64,
|
||||
}
|
||||
unsafe impl ByteValued for CopyfilerangeIn {}
|
||||
|
||||
bitflags! {
|
||||
pub struct SetupmappingFlags: u64 {
|
||||
const WRITE = 0x1;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
use std::collections::btree_map;
|
||||
use std::collections::BTreeMap;
|
||||
use std::convert::TryInto;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
@ -1644,4 +1645,59 @@ impl FileSystem for PassthroughFs {
|
||||
Ok(res as u64)
|
||||
}
|
||||
}
|
||||
|
||||
fn copyfilerange(
|
||||
&self,
|
||||
_ctx: Context,
|
||||
inode_in: Inode,
|
||||
handle_in: Handle,
|
||||
offset_in: u64,
|
||||
inode_out: Inode,
|
||||
handle_out: Handle,
|
||||
offset_out: u64,
|
||||
len: u64,
|
||||
flags: u64,
|
||||
) -> io::Result<usize> {
|
||||
let data_in = self
|
||||
.handles
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(&handle_in)
|
||||
.filter(|hd| hd.inode == inode_in)
|
||||
.map(Arc::clone)
|
||||
.ok_or_else(ebadf)?;
|
||||
|
||||
// Take just a read lock as we're not going to alter the file descriptor offset.
|
||||
let fd_in = data_in.file.read().unwrap().as_raw_fd();
|
||||
|
||||
let data_out = self
|
||||
.handles
|
||||
.read()
|
||||
.unwrap()
|
||||
.get(&handle_out)
|
||||
.filter(|hd| hd.inode == inode_out)
|
||||
.map(Arc::clone)
|
||||
.ok_or_else(ebadf)?;
|
||||
|
||||
// Take just a read lock as we're not going to alter the file descriptor offset.
|
||||
let fd_out = data_out.file.read().unwrap().as_raw_fd();
|
||||
|
||||
// Safe because this will only modify `offset_in` and `offset_out` and we check
|
||||
// the return value.
|
||||
let res = unsafe {
|
||||
libc::copy_file_range(
|
||||
fd_in,
|
||||
&mut (offset_in as i64) as &mut _ as *mut _,
|
||||
fd_out,
|
||||
&mut (offset_out as i64) as &mut _ as *mut _,
|
||||
len.try_into().unwrap(),
|
||||
flags.try_into().unwrap(),
|
||||
)
|
||||
};
|
||||
if res < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(res as usize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -124,6 +124,7 @@ impl<F: FileSystem + Sync> Server<F> {
|
||||
x if x == Opcode::Readdirplus as u32 => self.readdirplus(in_header, r, w),
|
||||
x if x == Opcode::Rename2 as u32 => self.rename2(in_header, r, w),
|
||||
x if x == Opcode::Lseek as u32 => self.lseek(in_header, r, w),
|
||||
x if x == Opcode::CopyFileRange as u32 => self.copyfilerange(in_header, r, w),
|
||||
x if x == Opcode::SetupMapping as u32 => self.setupmapping(in_header, r, w, vu_req),
|
||||
x if x == Opcode::RemoveMapping as u32 => self.removemapping(in_header, r, w, vu_req),
|
||||
_ => reply_error(
|
||||
@ -1261,6 +1262,41 @@ impl<F: FileSystem + Sync> Server<F> {
|
||||
Err(e) => reply_error(e, in_header.unique, w),
|
||||
}
|
||||
}
|
||||
|
||||
fn copyfilerange(&self, in_header: InHeader, mut r: Reader, w: Writer) -> Result<usize> {
|
||||
let CopyfilerangeIn {
|
||||
fh_in,
|
||||
off_in,
|
||||
nodeid_out,
|
||||
fh_out,
|
||||
off_out,
|
||||
len,
|
||||
flags,
|
||||
..
|
||||
} = r.read_obj().map_err(Error::DecodeMessage)?;
|
||||
|
||||
match self.fs.copyfilerange(
|
||||
Context::from(in_header),
|
||||
in_header.nodeid.into(),
|
||||
fh_in.into(),
|
||||
off_in,
|
||||
nodeid_out.into(),
|
||||
fh_out.into(),
|
||||
off_out,
|
||||
len,
|
||||
flags,
|
||||
) {
|
||||
Ok(count) => {
|
||||
let out = WriteOut {
|
||||
size: count as u32,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
reply_ok(Some(out), None, in_header.unique, w)
|
||||
}
|
||||
Err(e) => reply_error(e, in_header.unique, w),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reply_ok<T: ByteValued>(
|
||||
|
Loading…
x
Reference in New Issue
Block a user