Commit 21e019c2 by Thomas Tanaka Committed by Stéphane Graber

Fix btrfs bus error on sparc on snapshot delete

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. Changes since v1: - include <byteswap.h> for bswap definition - include defined function name as a comment above BTRFS_SETGET_STACK_FUNCS Signed-off-by: 's avatarThomas Tanaka <thomas.tanaka@oracle.com> Acked-by: 's avatarSerge E. Hallyn <serge.hallyn@ubuntu.com>
parent 9a09badc
......@@ -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++;
......
......@@ -28,6 +28,7 @@
#include <linux/types.h> /* __le64, __l32 ... */
#include <stdbool.h>
#include <stdint.h>
#include <byteswap.h>
typedef uint8_t u8;
typedef uint16_t u16;
......@@ -317,6 +318,50 @@ 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); \
}
/* defined as btrfs_stack_root_ref_dirid */
BTRFS_SETGET_STACK_FUNCS(stack_root_ref_dirid, struct btrfs_root_ref, dirid, 64);
/* defined as btrfs_stack_root_ref_sequence */
BTRFS_SETGET_STACK_FUNCS(stack_root_ref_sequence, struct btrfs_root_ref, sequence, 64);
/* defined as btrfs_stack_root_ref_name_len */
BTRFS_SETGET_STACK_FUNCS(stack_root_ref_name_len, struct btrfs_root_ref, name_len, 16);
/* defined in bdev.h */
struct bdev;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment