mirror of
https://github.com/systemd/systemd.git
synced 2024-12-23 21:35:11 +03:00
copy: Introduce reflink() and reflink_full()
The kernel has had filesystem independent reflink ioctls for a while now, let's try to use them and fall back to the btrfs specific ones if they're not supported.
This commit is contained in:
parent
fafded0ce0
commit
b640e274a7
@ -10,6 +10,14 @@
|
||||
#define BLKGETDISKSEQ _IOR(0x12,128,__u64)
|
||||
#endif
|
||||
|
||||
#ifndef FICLONE
|
||||
#define FICLONE _IOW(0x94, 9, int)
|
||||
#endif
|
||||
|
||||
#ifndef FICLONERANGE
|
||||
#define FICLONERANGE _IOW(0x94, 13, struct file_clone_range)
|
||||
#endif
|
||||
|
||||
/* linux/fs.h or sys/mount.h */
|
||||
#ifndef MS_MOVE
|
||||
#define MS_MOVE 8192
|
||||
|
@ -138,7 +138,7 @@ static int raw_export_process(RawExport *e) {
|
||||
* reflink source to destination directly. Let's see
|
||||
* if this works. */
|
||||
|
||||
r = btrfs_reflink(e->input_fd, e->output_fd);
|
||||
r = reflink(e->input_fd, e->output_fd);
|
||||
if (r >= 0) {
|
||||
r = 0;
|
||||
goto finish;
|
||||
@ -257,7 +257,7 @@ static int reflink_snapshot(int fd, const char *path) {
|
||||
(void) unlink(t);
|
||||
}
|
||||
|
||||
r = btrfs_reflink(fd, new_fd);
|
||||
r = reflink(fd, new_fd);
|
||||
if (r < 0) {
|
||||
safe_close(new_fd);
|
||||
return r;
|
||||
|
@ -335,7 +335,7 @@ static int raw_import_try_reflink(RawImport *i) {
|
||||
if ((uint64_t) p != (uint64_t) i->buffer_size)
|
||||
return 0;
|
||||
|
||||
r = btrfs_reflink(i->input_fd, i->output_fd);
|
||||
r = reflink(i->input_fd, i->output_fd);
|
||||
if (r >= 0)
|
||||
return 1;
|
||||
|
||||
|
@ -69,7 +69,7 @@ static int copy_cluster(
|
||||
ssize_t l;
|
||||
int r;
|
||||
|
||||
r = btrfs_clone_range(sfd, soffset, dfd, doffset, cluster_size);
|
||||
r = reflink_full(sfd, soffset, dfd, doffset, cluster_size);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
|
||||
|
@ -213,40 +213,6 @@ int btrfs_subvol_get_read_only_fd(int fd) {
|
||||
return !!(flags & BTRFS_SUBVOL_RDONLY);
|
||||
}
|
||||
|
||||
int btrfs_reflink(int infd, int outfd) {
|
||||
int r;
|
||||
|
||||
assert(infd >= 0);
|
||||
assert(outfd >= 0);
|
||||
|
||||
/* Make sure we invoke the ioctl on a regular file, so that no device driver accidentally gets it. */
|
||||
|
||||
r = fd_verify_regular(outfd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return RET_NERRNO(ioctl(outfd, BTRFS_IOC_CLONE, infd));
|
||||
}
|
||||
|
||||
int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
|
||||
struct btrfs_ioctl_clone_range_args args = {
|
||||
.src_fd = infd,
|
||||
.src_offset = in_offset,
|
||||
.src_length = sz,
|
||||
.dest_offset = out_offset,
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(infd >= 0);
|
||||
assert(outfd >= 0);
|
||||
|
||||
r = fd_verify_regular(outfd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return RET_NERRNO(ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args));
|
||||
}
|
||||
|
||||
int btrfs_get_block_device_at(int dir_fd, const char *path, dev_t *ret) {
|
||||
struct btrfs_ioctl_fs_info_args fsi = {};
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
@ -46,9 +46,6 @@ typedef enum BtrfsRemoveFlags {
|
||||
int btrfs_is_subvol_fd(int fd);
|
||||
int btrfs_is_subvol(const char *path);
|
||||
|
||||
int btrfs_reflink(int infd, int outfd);
|
||||
int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz);
|
||||
|
||||
int btrfs_get_block_device_at(int dir_fd, const char *path, dev_t *ret);
|
||||
static inline int btrfs_get_block_device(const char *path, dev_t *ret) {
|
||||
return btrfs_get_block_device_at(AT_FDCWD, path, ret);
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/btrfs.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/sendfile.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <unistd.h>
|
||||
@ -19,6 +21,7 @@
|
||||
#include "fs-util.h"
|
||||
#include "io-util.h"
|
||||
#include "macro.h"
|
||||
#include "missing_fs.h"
|
||||
#include "missing_syscall.h"
|
||||
#include "mkdir-label.h"
|
||||
#include "mountpoint-util.h"
|
||||
@ -198,9 +201,9 @@ int copy_bytes_full(
|
||||
if (toffset >= 0) {
|
||||
|
||||
if (foffset == 0 && toffset == 0 && max_bytes == UINT64_MAX)
|
||||
r = btrfs_reflink(fdf, fdt); /* full file reflink */
|
||||
r = reflink(fdf, fdt); /* full file reflink */
|
||||
else
|
||||
r = btrfs_clone_range(fdf, foffset, fdt, toffset, max_bytes == UINT64_MAX ? 0 : max_bytes); /* partial reflink */
|
||||
r = reflink_full(fdf, foffset, fdt, toffset, max_bytes == UINT64_MAX ? 0 : max_bytes); /* partial reflink */
|
||||
if (r >= 0) {
|
||||
off_t t;
|
||||
|
||||
@ -1594,3 +1597,49 @@ int copy_xattr(int df, const char *from, int dt, const char *to, CopyFlags copy_
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int reflink(int infd, int outfd) {
|
||||
int r;
|
||||
|
||||
assert(infd >= 0);
|
||||
assert(outfd >= 0);
|
||||
|
||||
/* Make sure we invoke the ioctl on a regular file, so that no device driver accidentally gets it. */
|
||||
|
||||
r = fd_verify_regular(outfd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* FICLONE was introduced in Linux 4.5, so let's fall back to BTRFS_IOC_CLONE if it's not supported. */
|
||||
|
||||
r = ioctl(outfd, FICLONE, infd);
|
||||
if (r < 0 && ERRNO_IS_NOT_SUPPORTED(errno))
|
||||
r = ioctl(outfd, BTRFS_IOC_CLONE, infd);
|
||||
|
||||
return RET_NERRNO(r);
|
||||
}
|
||||
|
||||
assert_cc(sizeof(struct file_clone_range) == sizeof(struct btrfs_ioctl_clone_range_args));
|
||||
|
||||
int reflink_full(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz) {
|
||||
struct file_clone_range args = {
|
||||
.src_fd = infd,
|
||||
.src_offset = in_offset,
|
||||
.src_length = sz,
|
||||
.dest_offset = out_offset,
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(infd >= 0);
|
||||
assert(outfd >= 0);
|
||||
|
||||
r = fd_verify_regular(outfd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ioctl(outfd, FICLONERANGE, &args);
|
||||
if (r < 0 && ERRNO_IS_NOT_SUPPORTED(errno))
|
||||
r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args);
|
||||
|
||||
return RET_NERRNO(r);
|
||||
}
|
||||
|
@ -104,3 +104,6 @@ static inline int copy_rights(int fdf, int fdt) {
|
||||
return copy_rights_with_fallback(fdf, fdt, NULL); /* no fallback */
|
||||
}
|
||||
int copy_xattr(int df, const char *from, int dt, const char *to, CopyFlags copy_flags);
|
||||
|
||||
int reflink(int infd, int outfd);
|
||||
int reflink_full(int infd, uint64_t in_offset, int outfd, uint64_t out_offset, uint64_t sz);
|
||||
|
Loading…
Reference in New Issue
Block a user