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

Commit a236aed1 authored by Chris Mason's avatar Chris Mason
Browse files

Btrfs: Deal with failed writes in mirrored configurations

parent 4235298e
Loading
Loading
Loading
Loading
+15 −2
Original line number Original line Diff line number Diff line
@@ -1385,7 +1385,10 @@ int write_all_supers(struct btrfs_root *root)
	struct buffer_head *bh;
	struct buffer_head *bh;
	int ret;
	int ret;
	int do_barriers;
	int do_barriers;
	int max_errors;
	int total_errors = 0;


	max_errors = btrfs_super_num_devices(&root->fs_info->super_copy) - 1;
	do_barriers = !btrfs_test_opt(root, NOBARRIER);
	do_barriers = !btrfs_test_opt(root, NOBARRIER);


	sb = root->fs_info->sb_buffer;
	sb = root->fs_info->sb_buffer;
@@ -1433,8 +1436,14 @@ int write_all_supers(struct btrfs_root *root)
		} else {
		} else {
			ret = submit_bh(WRITE, bh);
			ret = submit_bh(WRITE, bh);
		}
		}
		BUG_ON(ret);
		if (ret)
			total_errors++;
	}
	if (total_errors > max_errors) {
		printk("btrfs: %d errors while writing supers\n", total_errors);
		BUG();
	}
	}
	total_errors = 0;


	list_for_each(cur, head) {
	list_for_each(cur, head) {
		dev = list_entry(cur, struct btrfs_device, dev_list);
		dev = list_entry(cur, struct btrfs_device, dev_list);
@@ -1454,13 +1463,17 @@ int write_all_supers(struct btrfs_root *root)
				wait_on_buffer(bh);
				wait_on_buffer(bh);
				BUG_ON(!buffer_uptodate(bh));
				BUG_ON(!buffer_uptodate(bh));
			} else {
			} else {
				BUG();
				total_errors++;
			}
			}


		}
		}
		dev->pending_io = NULL;
		dev->pending_io = NULL;
		brelse(bh);
		brelse(bh);
	}
	}
	if (total_errors > max_errors) {
		printk("btrfs: %d errors while writing supers\n", total_errors);
		BUG();
	}
	return 0;
	return 0;
}
}


+2 −2
Original line number Original line Diff line number Diff line
@@ -315,8 +315,8 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
	block_group_cache = &info->block_group_cache;
	block_group_cache = &info->block_group_cache;
	total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);
	total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy);


	if (!owner)
	if (data & BTRFS_BLOCK_GROUP_METADATA)
		factor = 10;
		factor = 9;


	bit = block_group_state_bits(data);
	bit = block_group_state_bits(data);


+14 −3
Original line number Original line Diff line number Diff line
@@ -1425,6 +1425,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
	int stripe_index;
	int stripe_index;
	int i;
	int i;
	int num_stripes;
	int num_stripes;
	int max_errors = 0;
	struct btrfs_multi_bio *multi = NULL;
	struct btrfs_multi_bio *multi = NULL;


	if (multi_ret && !(rw & (1 << BIO_RW))) {
	if (multi_ret && !(rw & (1 << BIO_RW))) {
@@ -1436,6 +1437,8 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
				GFP_NOFS);
				GFP_NOFS);
		if (!multi)
		if (!multi)
			return -ENOMEM;
			return -ENOMEM;

		atomic_set(&multi->error, 0);
	}
	}


	spin_lock(&em_tree->lock);
	spin_lock(&em_tree->lock);
@@ -1462,8 +1465,10 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
		if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
		if (map->type & (BTRFS_BLOCK_GROUP_RAID1 |
				 BTRFS_BLOCK_GROUP_DUP)) {
				 BTRFS_BLOCK_GROUP_DUP)) {
			stripes_required = map->num_stripes;
			stripes_required = map->num_stripes;
			max_errors = 1;
		} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
		} else if (map->type & BTRFS_BLOCK_GROUP_RAID10) {
			stripes_required = map->sub_stripes;
			stripes_required = map->sub_stripes;
			max_errors = 1;
		}
		}
	}
	}
	if (multi_ret && rw == WRITE &&
	if (multi_ret && rw == WRITE &&
@@ -1561,6 +1566,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw,
	if (multi_ret) {
	if (multi_ret) {
		*multi_ret = multi;
		*multi_ret = multi;
		multi->num_stripes = num_stripes;
		multi->num_stripes = num_stripes;
		multi->max_errors = max_errors;
	}
	}
out:
out:
	free_extent_map(em);
	free_extent_map(em);
@@ -1598,14 +1604,19 @@ static int end_bio_multi_stripe(struct bio *bio,
		return 1;
		return 1;
#endif
#endif
	if (err)
	if (err)
		multi->error = err;
		atomic_inc(&multi->error);


	if (atomic_dec_and_test(&multi->stripes_pending)) {
	if (atomic_dec_and_test(&multi->stripes_pending)) {
		bio->bi_private = multi->private;
		bio->bi_private = multi->private;
		bio->bi_end_io = multi->end_io;
		bio->bi_end_io = multi->end_io;


		if (!err && multi->error)
		/* only send an error to the higher layers if it is
			err = multi->error;
		 * beyond the tolerance of the multi-bio
		 */
		if (atomic_read(&multi->error) > multi->max_errors)
			err = -EIO;
		else
			err = 0;
		kfree(multi);
		kfree(multi);


#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,23)
+2 −1
Original line number Original line Diff line number Diff line
@@ -90,7 +90,8 @@ struct btrfs_multi_bio {
	atomic_t stripes_pending;
	atomic_t stripes_pending;
	bio_end_io_t *end_io;
	bio_end_io_t *end_io;
	void *private;
	void *private;
	int error;
	atomic_t error;
	int max_errors;
	int num_stripes;
	int num_stripes;
	struct btrfs_bio_stripe stripes[];
	struct btrfs_bio_stripe stripes[];
};
};