summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.c
diff options
context:
space:
mode:
authorYan Zheng <zheng.yan@oracle.com>2008-11-17 21:11:30 -0500
committerChris Mason <chris.mason@oracle.com>2008-11-17 21:11:30 -0500
commit2b82032c34ec40515d3c45c36cd1961f37977de8 (patch)
treefbdfe7b13dd51983dfca4aeb75983b37ee186ff9 /fs/btrfs/disk-io.c
parentc146afad2c7fea6a366d4945c1bab9b03880f526 (diff)
downloadlinux-2b82032c34ec40515d3c45c36cd1961f37977de8.tar.bz2
Btrfs: Seed device support
Seed device is a special btrfs with SEEDING super flag set and can only be mounted in read-only mode. Seed devices allow people to create new btrfs on top of it. The new FS contains the same contents as the seed device, but it can be mounted in read-write mode. This patch does the following: 1) split code in btrfs_alloc_chunk into two parts. The first part does makes the newly allocated chunk usable, but does not do any operation that modifies the chunk tree. The second part does the the chunk tree modifications. This division is for the bootstrap step of adding storage to the seed device. 2) Update device management code to handle seed device. The basic idea is: For an FS grown from seed devices, its seed devices are put into a list. Seed devices are opened on demand at mounting time. If any seed device is missing or has been changed, btrfs kernel module will refuse to mount the FS. 3) make btrfs_find_block_group not return NULL when all block groups are read-only. Signed-off-by: Yan Zheng <zheng.yan@oracle.com>
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);