[lxc-devel] [PATCH] Fix btrfs bus error on sparc on snapshot delete

Thomas Tanaka thomas.tanaka at oracle.com
Thu Jan 14 19:20:53 UTC 2016


The following patch fixes memory alignment and endianness
issue while doing a snapshot deletion with btrfs as a
backing store on platform such as sparc.

The implementation is taken from btrfs-progs.

Signed-off-by: Thomas Tanaka <thomas.tanaka at oracle.com>
---
 src/lxc/bdev/lxcbtrfs.c |   28 +++++++++++++++-------------
 src/lxc/bdev/lxcbtrfs.h |   39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 13 deletions(-)

diff --git a/src/lxc/bdev/lxcbtrfs.c b/src/lxc/bdev/lxcbtrfs.c
index 2db7c87..0f8c1fc 100644
--- a/src/lxc/bdev/lxcbtrfs.c
+++ b/src/lxc/bdev/lxcbtrfs.c
@@ -565,7 +565,7 @@ static int btrfs_recursive_destroy(const char *path)
 	int fd;
 	struct btrfs_ioctl_search_args args;
 	struct btrfs_ioctl_search_key *sk = &args.key;
-	struct btrfs_ioctl_search_header *sh;
+	struct btrfs_ioctl_search_header sh;
 	struct btrfs_root_ref *ref;
 	struct my_btrfs_tree *tree;
 	int ret, i;
@@ -573,6 +573,7 @@ static int btrfs_recursive_destroy(const char *path)
 	int name_len;
 	char *name;
 	char *tmppath;
+	u64 dir_id;
 
 	fd = open(path, O_RDONLY);
 	if (fd < 0) {
@@ -624,21 +625,22 @@ static int btrfs_recursive_destroy(const char *path)
 
 		off = 0;
 		for (i = 0; i < sk->nr_items; i++) {
-			sh = (struct btrfs_ioctl_search_header *)(args.buf + off);
-			off += sizeof(*sh);
+			memcpy(&sh, args.buf + off, sizeof(sh));
+			off += sizeof(sh);
 			/*
 			 * A backref key with the name and dirid of the parent
 			 * comes followed by the reoot ref key which has the
 			 * name of the child subvol in question.
 			 */
-			if (sh->objectid != root_id && sh->type == BTRFS_ROOT_BACKREF_KEY) {
+			if (sh.objectid != root_id && sh.type == BTRFS_ROOT_BACKREF_KEY) {
 				ref = (struct btrfs_root_ref *)(args.buf + off);
-				name_len = ref->name_len;
+				name_len = btrfs_stack_root_ref_name_len(ref);
 				name = (char *)(ref + 1);
-				tmppath = get_btrfs_subvol_path(fd, sh->offset,
-						ref->dirid, name, name_len);
-				if (!add_btrfs_tree_node(tree, sh->objectid,
-							sh->offset, name,
+				dir_id = btrfs_stack_root_ref_dirid(ref);
+				tmppath = get_btrfs_subvol_path(fd, sh.offset,
+						dir_id, name, name_len);
+				if (!add_btrfs_tree_node(tree, sh.objectid,
+							sh.offset, name,
 							name_len, tmppath)) {
 					ERROR("Out of memory");
 					free_btrfs_tree(tree);
@@ -648,15 +650,15 @@ static int btrfs_recursive_destroy(const char *path)
 				}
 				free(tmppath);
 			}
-			off += sh->len;
+			off += sh.len;
 
 			/*
 			 * record the mins in sk so we can make sure the
 			 * next search doesn't repeat this root
 			 */
-			sk->min_objectid = sh->objectid;
-			sk->min_type = sh->type;
-			sk->min_offset = sh->offset;
+			sk->min_objectid = sh.objectid;
+			sk->min_type = sh.type;
+			sk->min_offset = sh.offset;
 		}
 		sk->nr_items = 4096;
 		sk->min_offset++;
diff --git a/src/lxc/bdev/lxcbtrfs.h b/src/lxc/bdev/lxcbtrfs.h
index e0adb7a..4ea2b4a 100644
--- a/src/lxc/bdev/lxcbtrfs.h
+++ b/src/lxc/bdev/lxcbtrfs.h
@@ -317,6 +317,45 @@ struct btrfs_ioctl_ino_lookup_args {
 #define BTRFS_LAST_FREE_OBJECTID -256ULL
 #define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL
 
+/* The followings are macro for correctly getting member of structures
+ * in both low and big endian platforms as per btrfs-progs 
+ */
+#ifdef __CHECKER__
+#define __force    __attribute__((force))
+#else
+#define __force
+#endif
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define cpu_to_le64(x) ((__force __le64)(u64)(bswap_64(x)))
+#define le64_to_cpu(x) ((__force u64)(__le64)(bswap_64(x)))
+#define cpu_to_le32(x) ((__force __le32)(u32)(bswap_32(x)))
+#define le32_to_cpu(x) ((__force u32)(__le32)(bswap_32(x)))
+#define cpu_to_le16(x) ((__force __le16)(u16)(bswap_16(x)))
+#define le16_to_cpu(x) ((__force u16)(__le16)(bswap_16(x)))
+#else
+#define cpu_to_le64(x) ((__force __le64)(u64)(x))
+#define le64_to_cpu(x) ((__force u64)(__le64)(x))
+#define cpu_to_le32(x) ((__force __le32)(u32)(x))
+#define le32_to_cpu(x) ((__force u32)(__le32)(x))
+#define cpu_to_le16(x) ((__force __le16)(u16)(x))
+#define le16_to_cpu(x) ((__force u16)(__le16)(x))
+#endif
+ 
+#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits)              \
+static inline u##bits btrfs_##name(type *s)                             \
+{                                                                       \
+        return le##bits##_to_cpu(s->member);                            \
+}                                                                       \
+static inline void btrfs_set_##name(type *s, u##bits val)               \
+{                                                                       \
+        s->member = cpu_to_le##bits(val);                               \
+}
+
+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_dirid, struct btrfs_root_ref, dirid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_sequence, struct btrfs_root_ref, sequence, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_root_ref_name_len, struct btrfs_root_ref, name_len, 16);
+
 /* defined in bdev.h */
 struct bdev;
 
-- 
1.7.1



More information about the lxc-devel mailing list