git » libjio » btrfs » tree

[btrfs] / libjio / btrfs.c

#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;
}