Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 321aecc6 authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: Add RAID10 support

parent e17cade2
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -197,6 +197,9 @@ struct btrfs_chunk {
	 * item in the btree
	 * item in the btree
	 */
	 */
	__le16 num_stripes;
	__le16 num_stripes;

	/* sub stripes only matter for raid10 */
	__le16 sub_stripes;
	struct btrfs_stripe stripe;
	struct btrfs_stripe stripe;
	/* additional stripes go here */
	/* additional stripes go here */
} __attribute__ ((__packed__));
} __attribute__ ((__packed__));
@@ -444,6 +447,7 @@ struct btrfs_csum_item {
#define BTRFS_BLOCK_GROUP_RAID0    (1 << 3)
#define BTRFS_BLOCK_GROUP_RAID0    (1 << 3)
#define BTRFS_BLOCK_GROUP_RAID1    (1 << 4)
#define BTRFS_BLOCK_GROUP_RAID1    (1 << 4)
#define BTRFS_BLOCK_GROUP_DUP	   (1 << 5)
#define BTRFS_BLOCK_GROUP_DUP	   (1 << 5)
#define BTRFS_BLOCK_GROUP_RAID10   (1 << 6)




struct btrfs_block_group_item {
struct btrfs_block_group_item {
@@ -757,6 +761,7 @@ BTRFS_SETGET_FUNCS(chunk_io_width, struct btrfs_chunk, io_width, 32);
BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32);
BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32);
BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64);
BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64);
BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16);
BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16);
BTRFS_SETGET_FUNCS(chunk_sub_stripes, struct btrfs_chunk, sub_stripes, 16);
BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64);
BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64);
BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64);
BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64);


@@ -778,6 +783,8 @@ BTRFS_SETGET_STACK_FUNCS(stack_chunk_sector_size, struct btrfs_chunk,
BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64);
BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64);
BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk,
BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk,
			 num_stripes, 16);
			 num_stripes, 16);
BTRFS_SETGET_STACK_FUNCS(stack_chunk_sub_stripes, struct btrfs_chunk,
			 sub_stripes, 16);
BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64);
BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64);
BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64);
BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64);


+1 −0
Original line number Original line Diff line number Diff line
@@ -1042,6 +1042,7 @@ static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
{
{
	u64 extra_flags = flags & (BTRFS_BLOCK_GROUP_RAID0 |
	u64 extra_flags = flags & (BTRFS_BLOCK_GROUP_RAID0 |
				   BTRFS_BLOCK_GROUP_RAID1 |
				   BTRFS_BLOCK_GROUP_RAID1 |
				   BTRFS_BLOCK_GROUP_RAID10 |
				   BTRFS_BLOCK_GROUP_DUP);
				   BTRFS_BLOCK_GROUP_DUP);
	if (extra_flags) {
	if (extra_flags) {
		if (flags & BTRFS_BLOCK_GROUP_DATA)
		if (flags & BTRFS_BLOCK_GROUP_DATA)
+41 −5
Original line number Original line Diff line number Diff line
@@ -33,6 +33,7 @@ struct map_lookup {
	int stripe_len;
	int stripe_len;
	int sector_size;
	int sector_size;
	int num_stripes;
	int num_stripes;
	int sub_stripes;
	struct btrfs_bio_stripe stripes[];
	struct btrfs_bio_stripe stripes[];
};
};


@@ -641,6 +642,7 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
	u64 avail;
	u64 avail;
	u64 max_avail = 0;
	u64 max_avail = 0;
	int num_stripes = 1;
	int num_stripes = 1;
	int sub_stripes = 0;
	int looped = 0;
	int looped = 0;
	int ret;
	int ret;
	int index;
	int index;
@@ -658,6 +660,13 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
		num_stripes = min_t(u64, 2,
		num_stripes = min_t(u64, 2,
				  btrfs_super_num_devices(&info->super_copy));
				  btrfs_super_num_devices(&info->super_copy));
	}
	}
	if (type & (BTRFS_BLOCK_GROUP_RAID10)) {
		num_stripes = btrfs_super_num_devices(&info->super_copy);
		if (num_stripes < 4)
			return -ENOSPC;
		num_stripes &= ~(u32)1;
		sub_stripes = 2;
	}
again:
again:
	INIT_LIST_HEAD(&private_devs);
	INIT_LIST_HEAD(&private_devs);
	cur = dev_list->next;
	cur = dev_list->next;
@@ -714,6 +723,8 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,


	if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP))
	if (type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_DUP))
		*num_bytes = calc_size;
		*num_bytes = calc_size;
	else if (type & BTRFS_BLOCK_GROUP_RAID10)
		*num_bytes = calc_size * num_stripes / sub_stripes;
	else
	else
		*num_bytes = calc_size * num_stripes;
		*num_bytes = calc_size * num_stripes;


@@ -760,12 +771,14 @@ printk("alloc chunk start %Lu size %Lu from dev %Lu type %Lu\n", key.offset, cal
	btrfs_set_stack_chunk_io_align(chunk, stripe_len);
	btrfs_set_stack_chunk_io_align(chunk, stripe_len);
	btrfs_set_stack_chunk_io_width(chunk, stripe_len);
	btrfs_set_stack_chunk_io_width(chunk, stripe_len);
	btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize);
	btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize);
	btrfs_set_stack_chunk_sub_stripes(chunk, sub_stripes);
	map->sector_size = extent_root->sectorsize;
	map->sector_size = extent_root->sectorsize;
	map->stripe_len = stripe_len;
	map->stripe_len = stripe_len;
	map->io_align = stripe_len;
	map->io_align = stripe_len;
	map->io_width = stripe_len;
	map->io_width = stripe_len;
	map->type = type;
	map->type = type;
	map->num_stripes = num_stripes;
	map->num_stripes = num_stripes;
	map->sub_stripes = sub_stripes;


	ret = btrfs_insert_item(trans, chunk_root, &key, chunk,
	ret = btrfs_insert_item(trans, chunk_root, &key, chunk,
				btrfs_chunk_item_size(num_stripes));
				btrfs_chunk_item_size(num_stripes));
@@ -832,6 +845,8 @@ int btrfs_num_copies(struct btrfs_mapping_tree *map_tree, u64 logical, u64 len)
	map = (struct map_lookup *)em->bdev;
	map = (struct map_lookup *)em->bdev;
	if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1))
	if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1))
		ret = map->num_stripes;
		ret = map->num_stripes;
	else if (map->type & BTRFS_BLOCK_GROUP_RAID10)
		ret = map->sub_stripes;
	else
	else
		ret = 1;
		ret = 1;
	free_extent_map(em);
	free_extent_map(em);
@@ -849,6 +864,7 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
	u64 stripe_offset;
	u64 stripe_offset;
	u64 stripe_nr;
	u64 stripe_nr;
	int stripes_allocated = 8;
	int stripes_allocated = 8;
	int stripes_required = 1;
	int stripe_index;
	int stripe_index;
	int i;
	int i;
	struct btrfs_multi_bio *multi = NULL;
	struct btrfs_multi_bio *multi = NULL;
@@ -877,10 +893,16 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
		mirror_num = 0;
		mirror_num = 0;


	/* if our multi bio struct is too small, back off and try again */
	/* if our multi bio struct is too small, back off and try again */
	if (multi_ret && (rw & (1 << BIO_RW)) &&
	if (rw & (1 << BIO_RW)) {
	    stripes_allocated < map->num_stripes &&
		if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
	    ((map->type & BTRFS_BLOCK_GROUP_RAID1) ||
				 BTRFS_BLOCK_GROUP_DUP)) {
	     (map->type & BTRFS_BLOCK_GROUP_DUP))) {
			stripes_required = map->num_stripes;
		} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
			stripes_required = map->sub_stripes;
		}
	}
	if (multi_ret && rw == WRITE &&
	    stripes_allocated < stripes_required) {
		stripes_allocated = map->num_stripes;
		stripes_allocated = map->num_stripes;
		free_extent_map(em);
		free_extent_map(em);
		kfree(multi);
		kfree(multi);
@@ -900,6 +922,7 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
	stripe_offset = offset - stripe_offset;
	stripe_offset = offset - stripe_offset;


	if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
	if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1 |
			 BTRFS_BLOCK_GROUP_RAID10 |
			 BTRFS_BLOCK_GROUP_DUP)) {
			 BTRFS_BLOCK_GROUP_DUP)) {
		/* we limit the length of each bio to what fits in a stripe */
		/* we limit the length of each bio to what fits in a stripe */
		*length = min_t(u64, em->len - offset,
		*length = min_t(u64, em->len - offset,
@@ -937,6 +960,19 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
			multi->num_stripes = map->num_stripes;
			multi->num_stripes = map->num_stripes;
		else if (mirror_num)
		else if (mirror_num)
			stripe_index = mirror_num - 1;
			stripe_index = mirror_num - 1;
	} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
		int factor = map->num_stripes / map->sub_stripes;
		int orig_stripe_nr = stripe_nr;

		stripe_index = do_div(stripe_nr, factor);
		stripe_index *= map->sub_stripes;

		if (rw & (1 << BIO_RW))
			multi->num_stripes = map->sub_stripes;
		else if (mirror_num)
			stripe_index += mirror_num - 1;
		else
			stripe_index += orig_stripe_nr % map->sub_stripes;
	} else {
	} else {
		/*
		/*
		 * after this do_div call, stripe_nr is the number of stripes
		 * after this do_div call, stripe_nr is the number of stripes
@@ -946,7 +982,6 @@ int btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
		stripe_index = do_div(stripe_nr, map->num_stripes);
		stripe_index = do_div(stripe_nr, map->num_stripes);
	}
	}
	BUG_ON(stripe_index >= map->num_stripes);
	BUG_ON(stripe_index >= map->num_stripes);
	BUG_ON(stripe_index != 0 && multi->num_stripes > 1);


	for (i = 0; i < multi->num_stripes; i++) {
	for (i = 0; i < multi->num_stripes; i++) {
		multi->stripes[i].physical =
		multi->stripes[i].physical =
@@ -1120,6 +1155,7 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
	map->sector_size = btrfs_chunk_sector_size(leaf, chunk);
	map->sector_size = btrfs_chunk_sector_size(leaf, chunk);
	map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
	map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk);
	map->type = btrfs_chunk_type(leaf, chunk);
	map->type = btrfs_chunk_type(leaf, chunk);
	map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk);
	for (i = 0; i < num_stripes; i++) {
	for (i = 0; i < num_stripes; i++) {
		map->stripes[i].physical =
		map->stripes[i].physical =
			btrfs_stripe_offset_nr(leaf, chunk, i);
			btrfs_stripe_offset_nr(leaf, chunk, i);