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:
Sergio Lopez 2020-03-20 14:08:26 +01:00 committed by Rob Bradford
parent b8cfdab8b6
commit 97e2d5d266
4 changed files with 121 additions and 0 deletions

View File

@ -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))

View File

@ -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;

View File

@ -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)
}
}
}

View File

@ -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>(