Browse Source

add FICLONE and copy_file_range to clonefile

If available FICLONE and copy_file_range will be tried in addition to sendfile
when copying data between two files. The fallback is a tradition read/write
loop. On systems that support these it should improve performance.
pull/516/head
Antonio SJ Musumeci 6 years ago
parent
commit
85026d5780
  1. 18
      src/fs_base_ioctl.hpp
  2. 111
      src/fs_clonefile.cpp
  3. 23
      src/fs_copy_file_range.cpp
  4. 40
      src/fs_copy_file_range.hpp
  5. 87
      src/fs_copy_file_range_linux.icpp
  6. 42
      src/fs_copy_file_range_unsupported.icpp
  7. 110
      src/fs_copyfile.cpp
  8. 24
      src/fs_copyfile.hpp
  9. 23
      src/fs_ficlone.cpp
  10. 26
      src/fs_ficlone.hpp
  11. 36
      src/fs_ficlone_linux.icpp
  12. 29
      src/fs_ficlone_unsupported.icpp

18
src/fs_base_ioctl.hpp

@ -25,10 +25,20 @@ namespace fs
static
inline
int
ioctl(const int fd,
const unsigned long request,
void *data)
ioctl(const int fd_,
const unsigned long request_,
void *data_)
{
return ::ioctl(fd,request,data);
return ::ioctl(fd_,request_,data_);
}
static
inline
int
ioctl(const int fd_,
const unsigned long request_,
const int int_)
{
return ::ioctl(fd_,request_,int_);
}
}

111
src/fs_clonefile.cpp

@ -18,106 +18,22 @@
#include "fs_attr.hpp"
#include "fs_base_chmod.hpp"
#include "fs_base_chown.hpp"
#include "fs_base_close.hpp"
#include "fs_base_fadvise.hpp"
#include "fs_base_fallocate.hpp"
#include "fs_base_lseek.hpp"
#include "fs_base_mkdir.hpp"
#include "fs_base_open.hpp"
#include "fs_base_read.hpp"
#include "fs_base_ftruncate.hpp"
#include "fs_base_stat.hpp"
#include "fs_base_utime.hpp"
#include "fs_base_write.hpp"
#include "fs_copy_file_range.hpp"
#include "fs_copyfile.hpp"
#include "fs_ficlone.hpp"
#include "fs_sendfile.hpp"
#include "fs_xattr.hpp"
#include <fcntl.h>
#include <stdlib.h>
#include <string>
#include <vector>
#ifndef O_LARGEFILE
# define O_LARGEFILE 0
#endif
#ifndef O_NOATIME
# define O_NOATIME 0
#endif
using std::string;
using std::vector;
int
writen(const int fd_,
const char *buf_,
const size_t count_)
{
size_t nleft;
ssize_t nwritten;
nleft = count_;
do
{
nwritten = fs::write(fd_,buf_,nleft);
if((nwritten == -1) && (errno == EINTR))
continue;
if(nwritten == -1)
return -1;
nleft -= nwritten;
buf_ += nwritten;
}
while(nleft > 0);
return count_;
}
static
int
copyfile_rw(const int src_fd_,
const int dst_fd_,
const size_t count_,
const size_t blocksize_)
{
ssize_t nr;
ssize_t nw;
ssize_t bufsize;
size_t totalwritten;
vector<char> buf;
bufsize = (blocksize_ * 16);
buf.resize(bufsize);
fs::lseek(src_fd_,0,SEEK_SET);
totalwritten = 0;
while(totalwritten < count_)
{
nr = fs::read(src_fd_,&buf[0],bufsize);
if(nr == 0)
return totalwritten;
if((nr == -1) && (errno == EINTR))
continue;
if(nr == -1)
return -1;
nw = writen(dst_fd_,&buf[0],nr);
if(nw == -1)
return -1;
totalwritten += nw;
}
return totalwritten;
}
static
int
copydata(const int src_fd_,
const int dst_fd_,
const size_t count_,
const size_t blocksize_)
const size_t count_)
{
int rv;
@ -125,12 +41,21 @@ copydata(const int src_fd_,
fs::fadvise_sequential(src_fd_,0,count_);
fs::fallocate(dst_fd_,0,0,count_);
fs::ftruncate(dst_fd_,count_);
rv = fs::sendfile(src_fd_,dst_fd_,count_);
if((rv == -1) && ((errno == EINVAL) || (errno == ENOSYS)))
return ::copyfile_rw(src_fd_,dst_fd_,count_,blocksize_);
rv = fs::ficlone(src_fd_,dst_fd_);
if((rv != -1) || ((rv == -1) && (errno != EOPNOTSUPP)))
return rv;
rv = fs::copy_file_range(src_fd_,dst_fd_,count_);
if((rv != -1) || ((rv == -1) && (errno != EOPNOTSUPP)))
return rv;
rv = fs::sendfile(src_fd_,dst_fd_,count_);
if((rv != -1) || ((rv == -1) && (errno != EINVAL) && (errno != ENOSYS)))
return rv;
return fs::copyfile(src_fd_,dst_fd_);
}
static
@ -163,7 +88,7 @@ namespace fs
if(rv == -1)
return -1;
rv = ::copydata(src_fd_,dst_fd_,src_st.st_size,src_st.st_blksize);
rv = ::copydata(src_fd_,dst_fd_,src_st.st_size);
if(rv == -1)
return -1;

23
src/fs_copy_file_range.cpp

@ -0,0 +1,23 @@
/*
ISC License
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef __linux__
# include "fs_copy_file_range_linux.icpp"
#else
# include "fs_copy_file_range_unsupported.icpp"
#endif

40
src/fs_copy_file_range.hpp

@ -0,0 +1,40 @@
/*
ISC License
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#include <sys/types.h>
#include <cstddef>
namespace fs
{
ssize_t
copy_file_range(const int fd_in_,
loff_t *off_in_,
const int fd_out_,
loff_t *off_out_,
const size_t len_,
const unsigned int flags_);
ssize_t
copy_file_range(const int fd_in_,
const int fd_out_,
const size_t len_,
const unsigned int flags_ = 0);
}

87
src/fs_copy_file_range_linux.icpp

@ -0,0 +1,87 @@
/*
ISC License
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#define _GNU_SOURCE
#include "errno.hpp"
#include <stdio.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
static
loff_t
copy_file_range_(int fd_in_,
loff_t *off_in_,
int fd_out_,
loff_t *off_out_,
size_t len_,
unsigned int flags_)
{
#ifdef SYS_copy_file_range
return ::syscall(SYS_copy_file_range,
fd_in_,
off_in_,
fd_out_,
off_out_,
len_,
flags_);
#else
return (errno=EOPNOTSUPP,-1);
#endif
}
namespace fs
{
ssize_t
copy_file_range(const int fd_in_,
loff_t *off_in_,
const int fd_out_,
loff_t *off_out_,
const size_t len_,
const unsigned int flags_)
{
return ::copy_file_range_(fd_in_,
off_in_,
fd_out_,
off_out_,
len_,
flags_);
}
ssize_t
copy_file_range(const int fd_in_,
const int fd_out_,
const size_t len_,
const unsigned int flags_)
{
loff_t off_in;
loff_t off_out;
off_in = 0;
off_out = 0;
return fs::copy_file_range(fd_in_,
&off_in,
fd_out_,
&off_out,
len_,
flags_);
}
}

42
src/fs_copy_file_range_unsupported.icpp

@ -0,0 +1,42 @@
/*
ISC License
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <cstddef>
namespace fs
{
ssize_t
copy_file_range(const int fd_in_,
loff_t *off_in_,
const int fd_out_,
loff_t *off_out_,
const size_t len_,
const unsigned int flags_)
{
return (errno=EOPNOTSUPP,-1);
}
ssize_t
copy_file_range(const int fd_in_,
const int fd_out_,
const size_t len_,
const unsigned int flags_)
{
return (errno=EOPNOTSUPP,-1);
}
}

110
src/fs_copyfile.cpp

@ -0,0 +1,110 @@
/*
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "errno.hpp"
#include "fs_base_stat.hpp"
#include "fs_base_lseek.hpp"
#include "fs_base_read.hpp"
#include "fs_base_write.hpp"
#include <vector>
using std::vector;
static
int
writen(const int fd_,
const char *buf_,
const size_t count_)
{
size_t nleft;
ssize_t nwritten;
nleft = count_;
do
{
nwritten = fs::write(fd_,buf_,nleft);
if((nwritten == -1) && (errno == EINTR))
continue;
if(nwritten == -1)
return -1;
nleft -= nwritten;
buf_ += nwritten;
}
while(nleft > 0);
return count_;
}
static
int
copyfile(const int src_fd_,
const int dst_fd_,
const size_t count_,
const size_t blocksize_)
{
ssize_t nr;
ssize_t nw;
ssize_t bufsize;
size_t totalwritten;
vector<char> buf;
bufsize = (blocksize_ * 16);
buf.resize(bufsize);
fs::lseek(src_fd_,0,SEEK_SET);
totalwritten = 0;
while(totalwritten < count_)
{
nr = fs::read(src_fd_,&buf[0],bufsize);
if(nr == 0)
return totalwritten;
if((nr == -1) && (errno == EINTR))
continue;
if(nr == -1)
return -1;
nw = writen(dst_fd_,&buf[0],nr);
if(nw == -1)
return -1;
totalwritten += nw;
}
return totalwritten;
}
namespace fs
{
int
copyfile(const int src_fd_,
const int dst_fd_)
{
int rv;
struct stat st;
rv = fs::fstat(src_fd_,st);
if(rv == -1)
return rv;
return ::copyfile(src_fd_,
dst_fd_,
st.st_size,
st.st_blksize);
}
}

24
src/fs_copyfile.hpp

@ -0,0 +1,24 @@
/*
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
namespace fs
{
int
copyfile(const int src_fd_,
const int dst_fd_);
}

23
src/fs_ficlone.cpp

@ -0,0 +1,23 @@
/*
ISC License
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef __linux__
# include "fs_ficlone_linux.icpp"
#else
# include "fs_ficlone_unsupported.icpp"
#endif

26
src/fs_ficlone.hpp

@ -0,0 +1,26 @@
/*
ISC License
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
namespace fs
{
int
ficlone(const int src_fd_,
const int dst_fd_);
}

36
src/fs_ficlone_linux.icpp

@ -0,0 +1,36 @@
/*
ISC License
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "errno.hpp"
#include "fs_base_ioctl.hpp"
#include <linux/fs.h>
namespace fs
{
int
ficlone(const int src_fd_,
const int dst_fd_)
{
#ifdef FICLONE
return fs::ioctl(dst_fd_,FICLONE,src_fd_);
#else
return (errno=EOPNOTSUPP,-1);
#endif
}
}

29
src/fs_ficlone_unsupported.icpp

@ -0,0 +1,29 @@
/*
ISC License
Copyright (c) 2018, Antonio SJ Musumeci <trapexit@spawn.link>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "errno.hpp"
namespace fs
{
int
ficlone(const int src_fd_,
const int dst_fd_)
{
return (errno=EOPNOTSUPP,-1);
}
}
Loading…
Cancel
Save