summary refs log tree commit diff
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c56
1 files changed, 35 insertions, 21 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index c599f0ee997a..82833e5d84b6 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -345,6 +345,25 @@ out:
 	return 0;
 }
 
+static int check_tree_block_fsid(struct btrfs_root *root,
+				 struct extent_buffer *eb)
+{
+	struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
+	u8 fsid[BTRFS_UUID_SIZE];
+	int ret = 1;
+
+	read_extent_buffer(eb, fsid, (unsigned long)btrfs_header_fsid(eb),
+			   BTRFS_FSID_SIZE);
+	while (fs_devices) {
+		if (!memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE)) {
+			ret = 0;
+			break;
+		}
+		fs_devices = fs_devices->seed;
+	}
+	return ret;
+}
+
 int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
 			       struct extent_state *state)
 {
@@ -382,9 +401,7 @@ int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
 		ret = -EIO;
 		goto err;
 	}
-	if (memcmp_extent_buffer(eb, root->fs_info->fsid,
-				 (unsigned long)btrfs_header_fsid(eb),
-				 BTRFS_FSID_SIZE)) {
+	if (check_tree_block_fsid(root, eb)) {
 		printk("bad fsid on block %Lu\n", eb->start);
 		ret = -EIO;
 		goto err;
@@ -1558,9 +1575,11 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 	if (!btrfs_super_root(disk_super))
 		goto fail_sb_buffer;
 
-	err = btrfs_parse_options(tree_root, options);
-	if (err)
+	ret = btrfs_parse_options(tree_root, options);
+	if (ret) {
+		err = ret;
 		goto fail_sb_buffer;
+	}
 
 	/*
 	 * we need to start all the end_io workers up front because the
@@ -1610,18 +1629,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 	btrfs_start_workers(&fs_info->endio_write_workers,
 			    fs_info->thread_pool_size);
 
-	err = -EINVAL;
-	if (btrfs_super_num_devices(disk_super) > fs_devices->open_devices) {
-		printk("Btrfs: wanted %llu devices, but found %llu\n",
-		       (unsigned long long)btrfs_super_num_devices(disk_super),
-		       (unsigned long long)fs_devices->open_devices);
-		if (btrfs_test_opt(tree_root, DEGRADED))
-			printk("continuing in degraded mode\n");
-		else {
-			goto fail_sb_buffer;
-		}
-	}
-
 	fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
 	fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
 				    4 * 1024 * 1024 / PAGE_CACHE_SIZE);
@@ -1672,7 +1679,10 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 	mutex_lock(&fs_info->chunk_mutex);
 	ret = btrfs_read_chunk_tree(chunk_root);
 	mutex_unlock(&fs_info->chunk_mutex);
-	BUG_ON(ret);
+	if (ret) {
+		printk("btrfs: failed to read chunk tree on %s\n", sb->s_id);
+		goto fail_chunk_root;
+	}
 
 	btrfs_close_extra_devices(fs_devices);
 
@@ -1684,7 +1694,7 @@ struct btrfs_root *open_ctree(struct super_block *sb,
 					  btrfs_super_root(disk_super),
 					  blocksize, generation);
 	if (!tree_root->node)
-		goto fail_sb_buffer;
+		goto fail_chunk_root;
 
 
 	ret = find_and_setup_root(tree_root, fs_info,
@@ -1753,6 +1763,8 @@ fail_extent_root:
 	free_extent_buffer(extent_root->node);
 fail_tree_root:
 	free_extent_buffer(tree_root->node);
+fail_chunk_root:
+	free_extent_buffer(chunk_root->node);
 fail_sys_array:
 fail_sb_buffer:
 	btrfs_stop_workers(&fs_info->fixup_workers);
@@ -1823,9 +1835,10 @@ int write_all_supers(struct btrfs_root *root)
 			total_errors++;
 			continue;
 		}
-		if (!dev->in_fs_metadata)
+		if (!dev->in_fs_metadata || !dev->writeable)
 			continue;
 
+		btrfs_set_stack_device_generation(dev_item, 0);
 		btrfs_set_stack_device_type(dev_item, dev->type);
 		btrfs_set_stack_device_id(dev_item, dev->devid);
 		btrfs_set_stack_device_total_bytes(dev_item, dev->total_bytes);
@@ -1834,6 +1847,7 @@ int write_all_supers(struct btrfs_root *root)
 		btrfs_set_stack_device_io_width(dev_item, dev->io_width);
 		btrfs_set_stack_device_sector_size(dev_item, dev->sector_size);
 		memcpy(dev_item->uuid, dev->uuid, BTRFS_UUID_SIZE);
+		memcpy(dev_item->fsid, dev->fs_devices->fsid, BTRFS_UUID_SIZE);
 		flags = btrfs_super_flags(sb);
 		btrfs_set_super_flags(sb, flags | BTRFS_HEADER_FLAG_WRITTEN);
 
@@ -1881,7 +1895,7 @@ int write_all_supers(struct btrfs_root *root)
 		dev = list_entry(cur, struct btrfs_device, dev_list);
 		if (!dev->bdev)
 			continue;
-		if (!dev->in_fs_metadata)
+		if (!dev->in_fs_metadata || !dev->writeable)
 			continue;
 
 		BUG_ON(!dev->pending_io);