git » libjio » commit bbfa7b7

WIP: btrfs_clone_range support

author Alberto Bertogli
2009-09-26 18:14:01 UTC
committer Alberto Bertogli
2009-09-26 18:42:39 UTC
parent 1ee54b0c2e244ddcba943208bb19ddb66ece2b60

WIP: btrfs_clone_range support

libjio/Makefile +2 -2
libjio/btrfs-ioctl.h +75 -0
libjio/btrfs.c +55 -0
libjio/btrfs.h +16 -0
libjio/journal.c +17 -5
libjio/journal.h +2 -0
libjio/trans.c +15 -0
libjio/trans.h +2 -0

diff --git a/libjio/Makefile b/libjio/Makefile
index a32828f..54343db 100644
--- a/libjio/Makefile
+++ b/libjio/Makefile
@@ -64,8 +64,8 @@ LIB_VER=1.00
 LIB_SO_VER=1
 
 
-OBJS = $(addprefix $O/,autosync.o checksum.o common.o compat.o trans.o \
-               check.o journal.o unix.o ansi.o)
+OBJS = $(addprefix $O/,autosync.o btrfs.o checksum.o common.o compat.o \
+               trans.o check.o journal.o unix.o ansi.o)
 
 
 # targets
diff --git a/libjio/btrfs-ioctl.h b/libjio/btrfs-ioctl.h
new file mode 100644
index 0000000..7c42513
--- /dev/null
+++ b/libjio/btrfs-ioctl.h
@@ -0,0 +1,75 @@
+
+/* The following was copied from Linux 2.6.31's kernel source, and the
+ * #include <asm/types.h> line was added to permit inclusion from userspace
+ * applications. */
+
+/*
+ * Copyright (C) 2007 Oracle.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __IOCTL_
+#define __IOCTL_
+#include <asm/types.h>
+#include <linux/ioctl.h>
+
+#define BTRFS_IOCTL_MAGIC 0x94
+#define BTRFS_VOL_NAME_MAX 255
+#define BTRFS_PATH_NAME_MAX 4087
+
+/* this should be 4k */
+struct btrfs_ioctl_vol_args {
+	__s64 fd;
+	char name[BTRFS_PATH_NAME_MAX + 1];
+};
+
+struct btrfs_ioctl_clone_range_args {
+  __s64 src_fd;
+  __u64 src_offset, src_length;
+  __u64 dest_offset;
+};
+
+#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
+				   struct btrfs_ioctl_vol_args)
+#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
+				   struct btrfs_ioctl_vol_args)
+#define BTRFS_IOC_RESIZE _IOW(BTRFS_IOCTL_MAGIC, 3, \
+				   struct btrfs_ioctl_vol_args)
+#define BTRFS_IOC_SCAN_DEV _IOW(BTRFS_IOCTL_MAGIC, 4, \
+				   struct btrfs_ioctl_vol_args)
+/* trans start and trans end are dangerous, and only for
+ * use by applications that know how to avoid the
+ * resulting deadlocks
+ */
+#define BTRFS_IOC_TRANS_START  _IO(BTRFS_IOCTL_MAGIC, 6)
+#define BTRFS_IOC_TRANS_END    _IO(BTRFS_IOCTL_MAGIC, 7)
+#define BTRFS_IOC_SYNC         _IO(BTRFS_IOCTL_MAGIC, 8)
+
+#define BTRFS_IOC_CLONE        _IOW(BTRFS_IOCTL_MAGIC, 9, int)
+#define BTRFS_IOC_ADD_DEV _IOW(BTRFS_IOCTL_MAGIC, 10, \
+				   struct btrfs_ioctl_vol_args)
+#define BTRFS_IOC_RM_DEV _IOW(BTRFS_IOCTL_MAGIC, 11, \
+				   struct btrfs_ioctl_vol_args)
+#define BTRFS_IOC_BALANCE _IOW(BTRFS_IOCTL_MAGIC, 12, \
+				   struct btrfs_ioctl_vol_args)
+
+#define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \
+				  struct btrfs_ioctl_clone_range_args)
+
+#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \
+				   struct btrfs_ioctl_vol_args)
+
+#endif
diff --git a/libjio/btrfs.c b/libjio/btrfs.c
new file mode 100644
index 0000000..2647df5
--- /dev/null
+++ b/libjio/btrfs.c
@@ -0,0 +1,55 @@
+
+#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"
+
+
+/* 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;
+	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;
+
+		r = btrfs_clone_range(jop->fd, journal_off, op->len, fd,
+				op->offset);
+		if (r != 0) {
+			perror("btrfs_clone_range");
+			return -1;
+		}
+		written += op->len;
+
+		/* skip the data + padding */
+		journal_off += op->len;
+		journal_off += (BSZ - (journal_off % BSZ)) % BSZ;
+	}
+
+	return written;
+}
+
diff --git a/libjio/btrfs.h b/libjio/btrfs.h
new file mode 100644
index 0000000..d351914
--- /dev/null
+++ b/libjio/btrfs.h
@@ -0,0 +1,16 @@
+
+#ifndef _LJ_BTRFS_H
+#define _LJ_BTRFS_H
+
+#include <sys/types.h>
+#include "trans.h"
+#include "journal.h"
+
+int btrfs_clone_range(int src_fd, off_t src_off, size_t src_len,
+		int dst_fd, off_t dst_off);
+
+/* TODO: better name for this, maybe put it inside trans.c */
+ssize_t attempt_btrfs_clone_ranges(int fd, struct operation *head_op,
+		struct journal_op *jop);
+
+#endif
diff --git a/libjio/journal.c b/libjio/journal.c
index fc34ffc..e2a4889 100644
--- a/libjio/journal.c
+++ b/libjio/journal.c
@@ -330,13 +330,20 @@ error:
 	return NULL;
 }
 
+
+static unsigned char empty_blk[BSZ];
+
 /** Save a single operation in the journal file */
 int journal_add_op(struct journal_op *jop, unsigned char *buf, size_t len,
 		off_t offset)
 {
 	ssize_t rv;
 	struct on_disk_ophdr ophdr;
-	struct iovec iov[2];
+	struct iovec iov[3];
+
+	/* start at 4k boundary */
+	off_t curpos = lseek(jop->fd, 0, SEEK_CUR);
+	lseek(jop->fd, (BSZ - (curpos % BSZ)) % BSZ, SEEK_CUR);
 
 	ophdr.len = len;
 	ophdr.offset = offset;
@@ -347,14 +354,19 @@ int journal_add_op(struct journal_op *jop, unsigned char *buf, size_t len,
 	jop->csum = checksum_buf(jop->csum, (unsigned char *) &ophdr,
 			sizeof(ophdr));
 
-	iov[1].iov_base = (void *) buf;
-	iov[1].iov_len = len;
+	iov[1].iov_base = (void *) empty_blk;
+	iov[1].iov_len = BSZ - sizeof(ophdr);
+	jop->csum = checksum_buf(jop->csum, empty_blk, iov[1].iov_len);
+
+	/* this will be BSZ-aligned */
+	iov[2].iov_base = (void *) buf;
+	iov[2].iov_len = len;
 	jop->csum = checksum_buf(jop->csum, buf, len);
 
 	fiu_exit_on("jio/commit/tf_pre_addop");
 
-	rv = swritev(jop->fd, iov, 2);
-	if (rv != sizeof(ophdr) + len)
+	rv = swritev(jop->fd, iov, 3);
+	if (rv != iov[0].iov_len + iov[1].iov_len + iov[2].iov_len)
 		goto error;
 
 	fiu_exit_on("jio/commit/tf_addop");
diff --git a/libjio/journal.h b/libjio/journal.h
index bdc1445..57eff46 100644
--- a/libjio/journal.h
+++ b/libjio/journal.h
@@ -5,6 +5,8 @@
 #include <stdint.h>
 #include "libjio.h"
 
+/* filesystem block size */
+#define BSZ 4096
 
 struct journal_op {
 	int id;
diff --git a/libjio/trans.c b/libjio/trans.c
index 1f7b66f..e1d3899 100644
--- a/libjio/trans.c
+++ b/libjio/trans.c
@@ -21,6 +21,7 @@
 #include "compat.h"
 #include "journal.h"
 #include "trans.h"
+#include "btrfs.h"
 
 
 /*
@@ -329,6 +330,18 @@ ssize_t jtrans_commit(struct jtrans *ts)
 			goto unlink_exit;
 	}
 
+	/* Attempt to write to the real file using btrfs' clone_range ioctl,
+	 * and only resort to the normal write procedure if it fails.
+	 * We should also isolate the normal write procedure, and clean this
+	 * code up. */
+	r = attempt_btrfs_clone_ranges(ts->fs->fd, ts->op, jop);
+	if (r >= 0) {
+		printf("btrfs ok\n");
+		written = r;
+		goto write_success;
+	}
+	printf("btrfs fail\n");
+
 	/* now that we have a safe transaction file, let's apply it */
 	written = 0;
 	for (op = ts->op; op != NULL; op = op->next) {
@@ -358,6 +371,8 @@ ssize_t jtrans_commit(struct jtrans *ts)
 		fiu_exit_on("jio/commit/wrote_op");
 	}
 
+write_success:
+
 	fiu_exit_on("jio/commit/wrote_all_ops");
 
 	if (jop && (ts->flags & J_LINGER)) {
diff --git a/libjio/trans.h b/libjio/trans.h
index 466c2d9..b033db8 100644
--- a/libjio/trans.h
+++ b/libjio/trans.h
@@ -2,6 +2,8 @@
 #ifndef _TRANS_H
 #define _TRANS_H
 
+#include <stdint.h>		/* uint32_t and friends */
+
 struct operation;
 
 /** A transaction */