#include <sys/types.h> /* off_t, size_t */
#include <sys/ioctl.h> /* ioctl() */
#include "btrfs-ioctl.h"
#include "btrfs.h"
#include "trans.h"
#include "journal.h"
#include "common.h"
/* Wrapper around btrfs' clone_range ioctl() */
int btrfs_clone_range(int src_fd, off_t src_off, size_t src_len,
int dst_fd, off_t dst_off)
{
int res;
struct btrfs_ioctl_clone_range_args args;
args.src_fd = src_fd;
args.src_offset = src_off;
args.src_length = src_len;
args.dest_offset = dst_off;
printf("%d %llu %zu -> %d %llu\n", src_fd, src_off, src_len, dst_fd,
dst_off);
res = ioctl(dst_fd, BTRFS_IOC_CLONE_RANGE, &args);
return res;
}
ssize_t attempt_btrfs_clone_ranges(int fd, struct operation *head_op,
struct journal_op *jop)
{
ssize_t r, written;
size_t clone_len;
struct operation *op;
off_t journal_off;
written = 0;
journal_off = BSZ;
for (op = head_op; op != NULL; op = op->next) {
/* skip the header + padding */
journal_off += BSZ;
/* clone must end in block size boundary too */
clone_len = op->len - op->len % BSZ;
r = btrfs_clone_range(jop->fd, journal_off, clone_len, fd,
op->offset);
if (r != 0) {
perror("btrfs_clone_range");
return -1;
}
/* copy the remainder data by hand */
if (op->len - clone_len) {
r = spwrite(fd, (unsigned char *) op->buf + clone_len,
op->len - clone_len,
op->offset + clone_len);
if (r != op->len - clone_len) {
perror("btrfs remainder");
return -1;
}
printf("btrfs clone rem ok: %zu\n", r);
}
written += op->len;
/* skip the data + padding */
journal_off += op->len;
journal_off += (BSZ - (journal_off % BSZ)) % BSZ;
}
return written;
}