unix: add UV_FS_COPYFILE_FICLONE support
UV_FS_COPYFILE_FICLONE attemps to use copy-on-write semantics in uv_fs_copyfile(). If CoW is not available, it falls back to a normal copy operation. Refs: https://github.com/libuv/libuv/pull/1465 PR-URL: https://github.com/libuv/libuv/pull/1491 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
This commit is contained in:
parent
cb1acaa46f
commit
db918361eb
@ -249,6 +249,9 @@ API
|
||||
- `UV_FS_COPYFILE_EXCL`: If present, `uv_fs_copyfile()` will fail with
|
||||
`UV_EEXIST` if the destination path already exists. The default behavior
|
||||
is to overwrite the destination if it exists.
|
||||
- `UV_FS_COPYFILE_FICLONE`: If present, `uv_fs_copyfile()` will attempt to
|
||||
create a copy-on-write reflink. If the underlying platform does not
|
||||
support copy-on-write, then a fallback copy mechanism is used.
|
||||
|
||||
.. warning::
|
||||
If the destination path is created, but an error occurs while copying
|
||||
@ -258,6 +261,8 @@ API
|
||||
|
||||
.. versionadded:: 1.14.0
|
||||
|
||||
.. versionchanged:: 1.20.0 `UV_FS_COPYFILE_FICLONE` is supported.
|
||||
|
||||
.. c:function:: int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file out_fd, uv_file in_fd, int64_t in_offset, size_t length, uv_fs_cb cb)
|
||||
|
||||
Limited equivalent to :man:`sendfile(2)`.
|
||||
|
||||
@ -1190,6 +1190,12 @@ UV_EXTERN int uv_fs_write(uv_loop_t* loop,
|
||||
*/
|
||||
#define UV_FS_COPYFILE_EXCL 0x0001
|
||||
|
||||
/*
|
||||
* This flag can be used with uv_fs_copyfile() to attempt to create a reflink.
|
||||
* If copy-on-write is not supported, a fallback copy mechanism is used.
|
||||
*/
|
||||
#define UV_FS_COPYFILE_FICLONE 0x0002
|
||||
|
||||
UV_EXTERN int uv_fs_copyfile(uv_loop_t* loop,
|
||||
uv_fs_t* req,
|
||||
const char* path,
|
||||
|
||||
@ -62,6 +62,9 @@
|
||||
|
||||
#if defined(__APPLE__)
|
||||
# include <copyfile.h>
|
||||
#elif defined(__linux__) && !defined(FICLONE)
|
||||
# include <sys/ioctl.h>
|
||||
# define FICLONE _IOW(0x94, 9, int)
|
||||
#endif
|
||||
|
||||
#define INIT(subtype) \
|
||||
@ -790,6 +793,10 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
if (req->flags & UV_FS_COPYFILE_EXCL)
|
||||
flags |= COPYFILE_EXCL;
|
||||
|
||||
#ifdef COPYFILE_CLONE
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE)
|
||||
flags |= COPYFILE_CLONE;
|
||||
#endif
|
||||
return copyfile(req->path, req->new_path, NULL, flags);
|
||||
#else
|
||||
uv_fs_t fs_req;
|
||||
@ -842,6 +849,21 @@ static ssize_t uv__fs_copyfile(uv_fs_t* req) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
#ifdef FICLONE
|
||||
if (req->flags & UV_FS_COPYFILE_FICLONE) {
|
||||
if (ioctl(dstfd, FICLONE, srcfd) == -1) {
|
||||
/* If an error occurred that the sendfile fallback also won't handle,
|
||||
then exit. Otherwise, fall through to try using sendfile(). */
|
||||
if (errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) {
|
||||
err = -errno;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bytes_to_send = statsbuf.st_size;
|
||||
in_offset = 0;
|
||||
while (bytes_to_send != 0) {
|
||||
@ -1504,7 +1526,7 @@ int uv_fs_copyfile(uv_loop_t* loop,
|
||||
uv_fs_cb cb) {
|
||||
INIT(COPYFILE);
|
||||
|
||||
if (flags & ~UV_FS_COPYFILE_EXCL)
|
||||
if (flags & ~(UV_FS_COPYFILE_EXCL | UV_FS_COPYFILE_FICLONE))
|
||||
return UV_EINVAL;
|
||||
|
||||
PATH2;
|
||||
|
||||
@ -2334,7 +2334,7 @@ int uv_fs_copyfile(uv_loop_t* loop,
|
||||
|
||||
INIT(UV_FS_COPYFILE);
|
||||
|
||||
if (flags & ~UV_FS_COPYFILE_EXCL)
|
||||
if (flags & ~(UV_FS_COPYFILE_EXCL | UV_FS_COPYFILE_FICLONE))
|
||||
return UV_EINVAL;
|
||||
|
||||
err = fs__capture_path(req, path, new_path, cb != NULL);
|
||||
|
||||
@ -168,6 +168,13 @@ TEST_IMPL(fs_copyfile) {
|
||||
r = uv_fs_copyfile(loop, &req, fixture, dst, -1, fail_cb);
|
||||
ASSERT(r == UV_EINVAL);
|
||||
uv_run(loop, UV_RUN_DEFAULT);
|
||||
|
||||
/* Copies file using UV_FS_COPYFILE_FICLONE. */
|
||||
unlink(dst);
|
||||
r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_FICLONE, NULL);
|
||||
ASSERT(r == 0);
|
||||
handle_result(&req);
|
||||
|
||||
unlink(dst); /* Cleanup */
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user