update btrfs-progs for seed device support

This patch does the following:

1) Update device management code to match the kernel code.

2) Allocator fixes.

3) Add a program called btrfstune to set/clear the SEEDING
   super block flags.
master
Yan Zheng 2008-11-18 10:40:06 -05:00 committed by Chris Mason
parent 95470dfaf1
commit 4d1d3a59d6
9 changed files with 342 additions and 52 deletions

View File

@ -15,7 +15,7 @@ prefix ?= /usr/local
bindir = $(prefix)/bin
LIBS=-luuid
progs = btrfsctl btrfsck mkfs.btrfs debug-tree btrfs-show btrfs-vol
progs = btrfsctl btrfsck mkfs.btrfs debug-tree btrfs-show btrfs-vol btrfstune
# make C=1 to enable sparse
ifdef C
@ -52,6 +52,9 @@ mkfs.btrfs: $(objects) mkfs.o
debug-tree: $(objects) debug-tree.o
gcc $(CFLAGS) -o debug-tree $(objects) debug-tree.o $(LDFLAGS) $(LIBS)
btrfstune: $(objects) btrfstune.o
gcc $(CFLAGS) -o btrfstune $(objects) btrfstune.o $(LDFLAGS) $(LIBS)
dir-test: $(objects) dir-test.o
gcc $(CFLAGS) -o dir-test $(objects) dir-test.o $(LDFLAGS) $(LIBS)

126
btrfstune.c 100644
View File

@ -0,0 +1,126 @@
/*
* Copyright (C) 2008 Oracle. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 021110-1307, USA.
*/
#define _XOPEN_SOURCE 500
#define _GNU_SOURCE 1
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include "kerncompat.h"
#include "ctree.h"
#include "disk-io.h"
#include "transaction.h"
#include "utils.h"
#include "version.h"
static char *device;
int update_seeding_flag(struct btrfs_root *root, int set_flag)
{
struct btrfs_trans_handle *trans;
struct btrfs_super_block *disk_super;
u64 super_flags;
disk_super = &root->fs_info->super_copy;
super_flags = btrfs_super_flags(disk_super);
if (set_flag) {
if (super_flags & BTRFS_SUPER_FLAG_SEEDING) {
fprintf(stderr, "seeding flag is already set on %s\n",
device);
return 1;
}
super_flags |= BTRFS_SUPER_FLAG_SEEDING;
} else {
if (!(super_flags & BTRFS_SUPER_FLAG_SEEDING)) {
fprintf(stderr, "seeding flag is not set on %s\n",
device);
return 1;
}
super_flags &= ~BTRFS_SUPER_FLAG_SEEDING;
}
trans = btrfs_start_transaction(root, 1);
btrfs_set_super_flags(disk_super, super_flags);
btrfs_commit_transaction(trans, root);
return 0;
}
static void print_usage(void)
{
fprintf(stderr, "usage: btrfstune [options] device\n");
fprintf(stderr, "\t-S value\tenable/disable seeding\n");
}
int main(int argc, char *argv[])
{
struct btrfs_root *root;
int success = 0;
int seeding_flag = 0;
int seeding_value = 0;
int ret;
while(1) {
int c = getopt(argc, argv, "S:");
if (c < 0)
break;
switch(c) {
case 'S':
seeding_flag = 1;
seeding_value = atoi(optarg);
break;
default:
print_usage();
return 1;
}
}
argc = argc - optind;
device = argv[optind];
if (argc != 1) {
print_usage();
return 1;
}
if (check_mounted(device)) {
fprintf(stderr, "%s is mounted\n", device);
return 1;
}
root = open_ctree(device, 0, 1);
if (seeding_flag) {
ret = update_seeding_flag(root, seeding_value);
if (!ret)
success++;
}
if (success > 0) {
ret = 0;
} else {
root->fs_info->readonly = 1;
ret = 1;
}
close_ctree(root);
return ret;
}

View File

@ -112,6 +112,10 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
btrfs_set_header_owner(cow, new_root_objectid);
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
write_extent_buffer(cow, root->fs_info->fsid,
(unsigned long)btrfs_header_fsid(cow),
BTRFS_FSID_SIZE);
WARN_ON(btrfs_header_generation(buf) > trans->transid);
ret = btrfs_inc_ref(trans, new_root, buf, cow, NULL);
kfree(new_root);
@ -161,6 +165,10 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
btrfs_set_header_owner(cow, root->root_key.objectid);
btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN);
write_extent_buffer(cow, root->fs_info->fsid,
(unsigned long)btrfs_header_fsid(cow),
BTRFS_FSID_SIZE);
WARN_ON(btrfs_header_generation(buf) > trans->transid);
if (btrfs_header_generation(buf) != trans->transid) {
different_trans = 1;

18
ctree.h
View File

@ -160,6 +160,9 @@ struct btrfs_dev_item {
/* type and info about this device */
__le64 type;
/* expected generation for this device */
__le64 generation;
/* grouping information for allocation decisions */
__le32 dev_group;
@ -171,6 +174,9 @@ struct btrfs_dev_item {
/* btrfs generated uuid for this device */
u8 uuid[BTRFS_UUID_SIZE];
/* uuid of FS who owns this device */
u8 fsid[BTRFS_UUID_SIZE];
} __attribute__ ((__packed__));
struct btrfs_stripe {
@ -246,6 +252,8 @@ struct btrfs_header {
sizeof(struct btrfs_item) - \
sizeof(struct btrfs_file_extent_item))
#define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32)
/*
* this is a very generous portion of the super block, giving us
* room to translate 14 chunks with 3 stripes each.
@ -524,6 +532,7 @@ struct btrfs_block_group_cache {
u64 pinned;
u64 flags;
int cached;
int ro;
};
struct btrfs_extent_ops {
@ -744,6 +753,7 @@ BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64);
BTRFS_SETGET_FUNCS(device_group, struct btrfs_dev_item, dev_group, 32);
BTRFS_SETGET_FUNCS(device_seek_speed, struct btrfs_dev_item, seek_speed, 8);
BTRFS_SETGET_FUNCS(device_bandwidth, struct btrfs_dev_item, bandwidth, 8);
BTRFS_SETGET_FUNCS(device_generation, struct btrfs_dev_item, generation, 64);
BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64);
BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item,
@ -763,12 +773,19 @@ BTRFS_SETGET_STACK_FUNCS(stack_device_seek_speed, struct btrfs_dev_item,
seek_speed, 8);
BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item,
bandwidth, 8);
BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item,
generation, 64);
static inline char *btrfs_device_uuid(struct btrfs_dev_item *d)
{
return (char *)d + offsetof(struct btrfs_dev_item, uuid);
}
static inline char *btrfs_device_fsid(struct btrfs_dev_item *d)
{
return (char *)d + offsetof(struct btrfs_dev_item, fsid);
}
BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64);
BTRFS_SETGET_FUNCS(chunk_owner, struct btrfs_chunk, owner, 64);
BTRFS_SETGET_FUNCS(chunk_stripe_len, struct btrfs_chunk, stripe_len, 64);
@ -1259,6 +1276,7 @@ BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item,
/* struct btrfs_super_block */
BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64);
BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64);
BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block,
generation, 64);
BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64);

View File

@ -37,14 +37,24 @@
static int check_tree_block(struct btrfs_root *root, struct extent_buffer *buf)
{
if (buf->start != btrfs_header_bytenr(buf))
return 1;
if (memcmp_extent_buffer(buf, root->fs_info->fsid,
(unsigned long)btrfs_header_fsid(buf),
BTRFS_FSID_SIZE))
return 1;
return 0;
struct btrfs_fs_devices *fs_devices;
int ret = 1;
if (buf->start != btrfs_header_bytenr(buf))
return ret;
fs_devices = root->fs_info->fs_devices;
while (fs_devices) {
if (!memcmp_extent_buffer(buf, fs_devices->fsid,
(unsigned long)btrfs_header_fsid(buf),
BTRFS_FSID_SIZE)) {
ret = 0;
break;
}
fs_devices = fs_devices->seed;
}
return ret;
}
u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len)
@ -685,6 +695,10 @@ int write_all_supers(struct btrfs_root *root)
dev_item);
list_for_each(cur, head) {
dev = list_entry(cur, struct btrfs_device, dev_list);
if (!dev->writeable)
continue;
btrfs_set_device_generation(sb, dev_item, 0);
btrfs_set_device_type(sb, dev_item, dev->type);
btrfs_set_device_id(sb, dev_item, dev->devid);
btrfs_set_device_total_bytes(sb, dev_item, dev->total_bytes);
@ -695,6 +709,9 @@ int write_all_supers(struct btrfs_root *root)
write_extent_buffer(sb, dev->uuid,
(unsigned long)btrfs_device_uuid(dev_item),
BTRFS_UUID_SIZE);
write_extent_buffer(sb, dev->fs_devices->fsid,
(unsigned long)btrfs_device_fsid(dev_item),
BTRFS_UUID_SIZE);
sb->fd = dev->fd;
sb->dev_bytenr = sb->start;
btrfs_set_header_flag(sb, BTRFS_HEADER_FLAG_WRITTEN);

View File

@ -159,6 +159,35 @@ err:
return 0;
}
struct btrfs_block_group_cache *btrfs_lookup_first_block_group(struct
btrfs_fs_info *info,
u64 bytenr)
{
struct extent_io_tree *block_group_cache;
struct btrfs_block_group_cache *block_group = NULL;
u64 ptr;
u64 start;
u64 end;
int ret;
bytenr = max_t(u64, bytenr,
BTRFS_SUPER_INFO_OFFSET + BTRFS_SUPER_INFO_SIZE);
block_group_cache = &info->block_group_cache;
ret = find_first_extent_bit(block_group_cache,
bytenr, &start, &end,
BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA |
BLOCK_GROUP_SYSTEM);
if (ret) {
return NULL;
}
ret = get_state_private(block_group_cache, start, &ptr);
if (ret)
return NULL;
block_group = (struct btrfs_block_group_cache *)(unsigned long)ptr;
return block_group;
}
struct btrfs_block_group_cache *btrfs_lookup_block_group(struct
btrfs_fs_info *info,
u64 bytenr)
@ -203,7 +232,6 @@ static int noinline find_search_start(struct btrfs_root *root,
u64 last;
u64 start = 0;
u64 end = 0;
u64 cache_miss = 0;
u64 search_start = *start_ret;
int wrapped = 0;
@ -216,7 +244,7 @@ again:
goto out;
last = max(search_start, cache->key.objectid);
if (!block_group_bits(cache, data)) {
if (cache->ro || !block_group_bits(cache, data)) {
goto new_group;
}
@ -224,20 +252,17 @@ again:
ret = find_first_extent_bit(&root->fs_info->free_space_cache,
last, &start, &end, EXTENT_DIRTY);
if (ret) {
if (!cache_miss)
cache_miss = last;
goto new_group;
}
start = max(last, start);
last = end + 1;
if (last - start < num) {
if (last == cache->key.objectid + cache->key.offset)
cache_miss = start;
continue;
}
if (start + num > cache->key.objectid + cache->key.offset)
if (start + num > cache->key.objectid + cache->key.offset) {
goto new_group;
}
*start_ret = start;
return 0;
}
@ -253,7 +278,7 @@ out:
new_group:
last = cache->key.objectid + cache->key.offset;
wrapped:
cache = btrfs_lookup_block_group(root->fs_info, last);
cache = btrfs_lookup_first_block_group(root->fs_info, last);
if (!cache) {
no_cache:
if (!wrapped) {
@ -263,16 +288,12 @@ no_cache:
}
goto out;
}
if (cache_miss && !cache->cached) {
cache_block_group(root, cache);
last = cache_miss;
cache = btrfs_lookup_block_group(root->fs_info, last);
}
cache = btrfs_find_block_group(root, cache, last, data, 0);
cache = btrfs_find_block_group(root, cache, last, data, 0);
if (!cache)
goto no_cache;
*cache_ret = cache;
cache_miss = 0;
goto again;
}
@ -328,7 +349,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
if (search_start) {
struct btrfs_block_group_cache *shint;
shint = btrfs_lookup_block_group(info, search_start);
if (shint && block_group_bits(shint, data)) {
if (shint && !shint->ro && block_group_bits(shint, data)) {
used = btrfs_block_group_used(&shint->item);
if (used + shint->pinned <
div_factor(shint->key.offset, factor)) {
@ -336,7 +357,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root,
}
}
}
if (hint && block_group_bits(hint, data)) {
if (hint && !hint->ro && block_group_bits(hint, data)) {
used = btrfs_block_group_used(&hint->item);
if (used + hint->pinned <
div_factor(hint->key.offset, factor)) {
@ -367,7 +388,7 @@ again:
last = cache->key.objectid + cache->key.offset;
used = btrfs_block_group_used(&cache->item);
if (block_group_bits(cache, data)) {
if (!cache->ro && block_group_bits(cache, data)) {
if (full_search)
free_check = cache->key.offset;
else
@ -1705,11 +1726,8 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
WARN_ON(num_bytes < root->sectorsize);
btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
if (search_end == (u64)-1)
search_end = btrfs_super_total_bytes(&info->super_copy);
if (hint_byte) {
block_group = btrfs_lookup_block_group(info, hint_byte);
block_group = btrfs_lookup_first_block_group(info, hint_byte);
if (!block_group)
hint_byte = search_start;
block_group = btrfs_find_block_group(root, block_group,
@ -1724,9 +1742,10 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans,
check_failed:
if (!block_group) {
block_group = btrfs_lookup_block_group(info, search_start);
block_group = btrfs_lookup_first_block_group(info,
search_start);
if (!block_group)
block_group = btrfs_lookup_block_group(info,
block_group = btrfs_lookup_first_block_group(info,
orig_search_start);
}
ret = find_search_start(root, &block_group, &search_start,
@ -1738,9 +1757,6 @@ check_failed:
ins->objectid = search_start;
ins->offset = num_bytes;
if (ins->objectid + num_bytes >= search_end)
goto enospc;
if (ins->objectid + num_bytes >
block_group->key.objectid + block_group->key.offset) {
search_start = block_group->key.objectid +
@ -1775,8 +1791,8 @@ check_failed:
return 0;
new_group:
if (search_start + num_bytes >= search_end) {
enospc:
block_group = btrfs_lookup_first_block_group(info, search_start);
if (!block_group) {
search_start = orig_search_start;
if (full_scan) {
ret = -ENOSPC;
@ -1789,7 +1805,6 @@ enospc:
} else
wrapped = 1;
}
block_group = btrfs_lookup_block_group(info, search_start);
cond_resched();
block_group = btrfs_find_block_group(root, block_group,
search_start, data, 0);
@ -2414,7 +2429,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
}
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
cache = kmalloc(sizeof(*cache), GFP_NOFS);
cache = kzalloc(sizeof(*cache), GFP_NOFS);
if (!cache) {
ret = -ENOMEM;
break;
@ -2438,6 +2453,8 @@ int btrfs_read_block_groups(struct btrfs_root *root)
bit = BLOCK_GROUP_METADATA;
}
set_avail_alloc_bits(info, cache->flags);
if (btrfs_chunk_readonly(root, cache->key.objectid))
cache->ro = 1;
ret = update_space_info(info, cache->flags, found_key.offset,
btrfs_block_group_used(&cache->item),
@ -2451,10 +2468,6 @@ int btrfs_read_block_groups(struct btrfs_root *root)
bit | EXTENT_LOCKED, GFP_NOFS);
set_state_private(block_group_cache, found_key.objectid,
(unsigned long)cache);
if (key.objectid >=
btrfs_super_total_bytes(&info->super_copy))
break;
}
ret = 0;
error:

View File

@ -96,7 +96,7 @@ int make_btrfs(int fd, const char *device, const char *label,
btrfs_set_super_root(&super, blocks[1]);
btrfs_set_super_chunk_root(&super, blocks[3]);
btrfs_set_super_total_bytes(&super, num_bytes);
btrfs_set_super_bytes_used(&super, first_free + 5 * leafsize);
btrfs_set_super_bytes_used(&super, 5 * leafsize);
btrfs_set_super_sectorsize(&super, sectorsize);
btrfs_set_super_leafsize(&super, leafsize);
btrfs_set_super_nodesize(&super, nodesize);
@ -252,6 +252,7 @@ int make_btrfs(int fd, const char *device, const char *label,
dev_item = btrfs_item_ptr(buf, nritems, struct btrfs_dev_item);
btrfs_set_device_id(buf, dev_item, 1);
btrfs_set_device_generation(buf, dev_item, 0);
btrfs_set_device_total_bytes(buf, dev_item, num_bytes);
btrfs_set_device_bytes_used(buf, dev_item,
BTRFS_MKFS_SYSTEM_GROUP_SIZE);
@ -263,6 +264,9 @@ int make_btrfs(int fd, const char *device, const char *label,
write_extent_buffer(buf, super.dev_item.uuid,
(unsigned long)btrfs_device_uuid(dev_item),
BTRFS_UUID_SIZE);
write_extent_buffer(buf, super.fsid,
(unsigned long)btrfs_device_fsid(dev_item),
BTRFS_UUID_SIZE);
read_extent_buffer(buf, &super.dev_item, (unsigned long)dev_item,
sizeof(*dev_item));
@ -456,6 +460,7 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
device->io_align = io_align;
device->sector_size = sectorsize;
device->fd = fd;
device->writeable = 1;
device->total_bytes = block_count;
device->bytes_used = 0;
device->total_ios = 0;
@ -489,6 +494,7 @@ int btrfs_add_to_fsid(struct btrfs_trans_handle *trans,
kfree(buf);
list_add(&device->dev_list, &root->fs_info->fs_devices->devices);
device->fs_devices = root->fs_info->fs_devices;
ret = btrfs_bootstrap_super_map(&root->fs_info->mapping_tree,
root->fs_info->fs_devices);
BUG_ON(ret);

110
volumes.c
View File

@ -91,7 +91,7 @@ static int device_list_add(const char *path,
fs_devices = find_fsid(disk_super->fsid);
if (!fs_devices) {
fs_devices = kmalloc(sizeof(*fs_devices), GFP_NOFS);
fs_devices = kzalloc(sizeof(*fs_devices), GFP_NOFS);
if (!fs_devices)
return -ENOMEM;
INIT_LIST_HEAD(&fs_devices->devices);
@ -127,6 +127,7 @@ static int device_list_add(const char *path,
device->bytes_used =
btrfs_stack_device_bytes_used(&disk_super->dev_item);
list_add(&device->dev_list, &fs_devices->devices);
device->fs_devices = fs_devices;
}
if (found_transid > fs_devices->latest_trans) {
@ -142,15 +143,24 @@ static int device_list_add(const char *path,
int btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
{
struct list_head *head = &fs_devices->devices;
struct btrfs_fs_devices *seed_devices;
struct list_head *cur;
struct btrfs_device *device;
list_for_each(cur, head) {
again:
list_for_each(cur, &fs_devices->devices) {
device = list_entry(cur, struct btrfs_device, dev_list);
close(device->fd);
device->fd = -1;
device->writeable = 0;
}
seed_devices = fs_devices->seed;
fs_devices->seed = NULL;
if (seed_devices) {
fs_devices = seed_devices;
goto again;
}
return 0;
}
@ -176,6 +186,8 @@ int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, int flags)
if (device->devid == fs_devices->lowest_devid)
fs_devices->lowest_bdev = fd;
device->fd = fd;
if (flags == O_RDWR)
device->writeable = 1;
}
return 0;
fail:
@ -504,6 +516,7 @@ int btrfs_add_device(struct btrfs_trans_handle *trans,
device->devid = free_devid;
btrfs_set_device_id(leaf, dev_item, device->devid);
btrfs_set_device_generation(leaf, dev_item, 0);
btrfs_set_device_type(leaf, dev_item, device->type);
btrfs_set_device_io_align(leaf, dev_item, device->io_align);
btrfs_set_device_io_width(leaf, dev_item, device->io_width);
@ -516,6 +529,8 @@ int btrfs_add_device(struct btrfs_trans_handle *trans,
ptr = (unsigned long)btrfs_device_uuid(dev_item);
write_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
ptr = (unsigned long)btrfs_device_fsid(dev_item);
write_extent_buffer(leaf, root->fs_info->fsid, ptr, BTRFS_UUID_SIZE);
btrfs_mark_buffer_dirty(leaf);
ret = 0;
@ -996,11 +1011,23 @@ out:
}
struct btrfs_device *btrfs_find_device(struct btrfs_root *root, u64 devid,
u8 *uuid)
u8 *uuid, u8 *fsid)
{
struct list_head *head = &root->fs_info->fs_devices->devices;
struct btrfs_device *device;
struct btrfs_fs_devices *cur_devices;
return __find_device(head, devid, uuid);
cur_devices = root->fs_info->fs_devices;
while (cur_devices) {
if (!fsid ||
!memcmp(cur_devices->fsid, fsid, BTRFS_UUID_SIZE)) {
device = __find_device(&cur_devices->devices,
devid, uuid);
if (device)
return device;
}
cur_devices = cur_devices->seed;
}
return NULL;
}
int btrfs_bootstrap_super_map(struct btrfs_mapping_tree *map_tree,
@ -1056,6 +1083,28 @@ int btrfs_bootstrap_super_map(struct btrfs_mapping_tree *map_tree,
return 0;
}
int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset)
{
struct cache_extent *ce;
struct map_lookup *map;
struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree;
int readonly = 0;
int i;
ce = find_first_cache_extent(&map_tree->cache_tree, chunk_offset);
BUG_ON(!ce);
map = container_of(ce, struct map_lookup, ce);
for (i = 0; i < map->num_stripes; i++) {
if (!map->stripes[i].dev->writeable) {
readonly = 1;
break;
}
}
return readonly;
}
static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
struct extent_buffer *leaf,
struct btrfs_chunk *chunk)
@ -1111,7 +1160,8 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
read_extent_buffer(leaf, uuid, (unsigned long)
btrfs_stripe_dev_uuid_nr(chunk, i),
BTRFS_UUID_SIZE);
map->stripes[i].dev = btrfs_find_device(root, devid, uuid);
map->stripes[i].dev = btrfs_find_device(root, devid, uuid,
NULL);
if (!map->stripes[i].dev) {
kfree(map);
return -EIO;
@ -1144,6 +1194,36 @@ static int fill_device_from_item(struct extent_buffer *leaf,
return 0;
}
static int open_seed_devices(struct btrfs_root *root, u8 *fsid)
{
struct btrfs_fs_devices *fs_devices;
int ret;
fs_devices = root->fs_info->fs_devices->seed;
while (fs_devices) {
if (!memcmp(fs_devices->fsid, fsid, BTRFS_UUID_SIZE)) {
ret = 0;
goto out;
}
fs_devices = fs_devices->seed;
}
fs_devices = find_fsid(fsid);
if (!fs_devices) {
ret = -ENOENT;
goto out;
}
ret = btrfs_open_devices(fs_devices, O_RDONLY);
if (ret)
goto out;
fs_devices->seed = root->fs_info->fs_devices->seed;
root->fs_info->fs_devices->seed = fs_devices;
out:
return ret;
}
static int read_one_dev(struct btrfs_root *root,
struct extent_buffer *leaf,
struct btrfs_dev_item *dev_item)
@ -1151,13 +1231,24 @@ static int read_one_dev(struct btrfs_root *root,
struct btrfs_device *device;
u64 devid;
int ret = 0;
u8 fs_uuid[BTRFS_UUID_SIZE];
u8 dev_uuid[BTRFS_UUID_SIZE];
devid = btrfs_device_id(leaf, dev_item);
read_extent_buffer(leaf, dev_uuid,
(unsigned long)btrfs_device_uuid(dev_item),
BTRFS_UUID_SIZE);
device = btrfs_find_device(root, devid, dev_uuid);
read_extent_buffer(leaf, fs_uuid,
(unsigned long)btrfs_device_fsid(dev_item),
BTRFS_UUID_SIZE);
if (memcmp(fs_uuid, root->fs_info->fsid, BTRFS_UUID_SIZE)) {
ret = open_seed_devices(root, fs_uuid);
if (ret)
return ret;
}
device = btrfs_find_device(root, devid, dev_uuid, fs_uuid);
if (!device) {
printk("warning devid %llu not found already\n",
(unsigned long long)devid);
@ -1284,6 +1375,7 @@ again:
struct btrfs_chunk *chunk;
chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
ret = read_one_chunk(root, &found_key, leaf, chunk);
BUG_ON(ret);
}
path->slots[0]++;
}

View File

@ -21,11 +21,14 @@
struct btrfs_device {
struct list_head dev_list;
struct btrfs_root *dev_root;
struct btrfs_fs_devices *fs_devices;
u64 total_ios;
int fd;
int writeable;
char *name;
/* these are read off the super block, only in the progs */
@ -69,6 +72,9 @@ struct btrfs_fs_devices {
int lowest_bdev;
struct list_head devices;
struct list_head list;
int seeding;
struct btrfs_fs_devices *seed;
};
struct btrfs_bio_stripe {
@ -120,4 +126,5 @@ struct list_head *btrfs_scanned_uuids(void);
int btrfs_add_system_chunk(struct btrfs_trans_handle *trans,
struct btrfs_root *root, struct btrfs_key *key,
struct btrfs_chunk *chunk, int item_size);
int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
#endif