Commit 0b86a832 authored by Chris Mason's avatar Chris Mason

Btrfs: Add support for multiple devices per filesystem

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 7f93bf8d
......@@ -6,7 +6,7 @@ btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
hash.o file-item.o inode-item.o inode-map.o disk-io.o \
transaction.o bit-radix.o inode.o file.o tree-defrag.o \
extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \
extent_io.o
extent_io.o volumes.o
ifeq ($(CONFIG_FS_POSIX_ACL),y)
btrfs-y += acl.o
......
......@@ -70,6 +70,14 @@ void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p)
memset(p, 0, sizeof(*p));
}
static void add_root_to_dirty_list(struct btrfs_root *root)
{
if (root->track_dirty && list_empty(&root->dirty_list)) {
list_add(&root->dirty_list,
&root->fs_info->dirty_cowonly_roots);
}
}
int btrfs_copy_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *buf,
......@@ -196,6 +204,7 @@ int __btrfs_cow_block(struct btrfs_trans_handle *trans,
root_gen, 0, 0, 1);
}
free_extent_buffer(buf);
add_root_to_dirty_list(root);
} else {
root_gen = btrfs_header_generation(parent);
btrfs_set_node_blockptr(parent, parent_slot,
......@@ -241,7 +250,7 @@ int btrfs_cow_block(struct btrfs_trans_handle *trans,
return 0;
}
search_start = buf->start & ~((u64)BTRFS_BLOCK_GROUP_SIZE - 1);
search_start = buf->start & ~((u64)(1024 * 1024 * 1024) - 1);
ret = __btrfs_cow_block(trans, root, buf, parent,
parent_slot, cow_ret, search_start, 0);
return ret;
......@@ -724,6 +733,7 @@ static int balance_level(struct btrfs_trans_handle *trans,
BUG_ON(ret);
root->node = child;
add_root_to_dirty_list(root);
path->nodes[level] = NULL;
clean_tree_block(trans, root, mid);
wait_on_tree_block_writeback(root, mid);
......@@ -1369,6 +1379,7 @@ static int noinline insert_new_root(struct btrfs_trans_handle *trans,
/* the super has an extra ref to root->node */
free_extent_buffer(root->node);
root->node = c;
add_root_to_dirty_list(root);
extent_buffer_get(c);
path->nodes[level] = c;
path->slots[level] = 0;
......@@ -2777,3 +2788,28 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path)
}
return 0;
}
int btrfs_previous_item(struct btrfs_root *root,
struct btrfs_path *path, u64 min_objectid,
int type)
{
struct btrfs_key found_key;
struct extent_buffer *leaf;
int ret;
while(1) {
if (path->slots[0] == 0) {
ret = btrfs_prev_leaf(root, path);
if (ret != 0)
return ret;
} else {
path->slots[0]--;
}
leaf = path->nodes[0];
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
if (found_key.type == type)
return 0;
}
return 1;
}
This diff is collapsed.
......@@ -28,6 +28,7 @@
#include "disk-io.h"
#include "transaction.h"
#include "btrfs_inode.h"
#include "volumes.h"
#include "print-tree.h"
#if 0
......@@ -234,6 +235,19 @@ static int btree_writepage_io_hook(struct page *page, u64 start, u64 end)
return 0;
}
static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio)
{
struct btrfs_root *root = BTRFS_I(inode)->root;
u64 offset;
offset = bio->bi_sector << 9;
if (offset == BTRFS_SUPER_INFO_OFFSET) {
bio->bi_bdev = root->fs_info->sb->s_bdev;
submit_bio(rw, bio);
return 0;
}
return btrfs_map_bio(BTRFS_I(inode)->root, rw, bio);
}
static int btree_writepage(struct page *page, struct writeback_control *wbc)
{
struct extent_io_tree *tree;
......@@ -345,6 +359,23 @@ int readahead_tree_block(struct btrfs_root *root, u64 bytenr, u32 blocksize)
return ret;
}
static int close_all_devices(struct btrfs_fs_info *fs_info)
{
struct list_head *list;
struct list_head *next;
struct btrfs_device *device;
list = &fs_info->devices;
while(!list_empty(list)) {
next = list->next;
list_del(next);
device = list_entry(next, struct btrfs_device, dev_list);
kfree(device->name);
kfree(device);
}
return 0;
}
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
u32 blocksize)
{
......@@ -420,6 +451,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
root->leafsize = leafsize;
root->stripesize = stripesize;
root->ref_cows = 0;
root->track_dirty = 0;
root->fs_info = fs_info;
root->objectid = objectid;
root->last_trans = 0;
......@@ -427,6 +460,8 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
root->last_inode_alloc = 0;
root->name = NULL;
root->in_sysfs = 0;
INIT_LIST_HEAD(&root->dirty_list);
memset(&root->root_key, 0, sizeof(root->root_key));
memset(&root->root_item, 0, sizeof(root->root_item));
memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
......@@ -634,6 +669,10 @@ struct btrfs_root *open_ctree(struct super_block *sb)
GFP_NOFS);
struct btrfs_fs_info *fs_info = kmalloc(sizeof(*fs_info),
GFP_NOFS);
struct btrfs_root *chunk_root = kmalloc(sizeof(struct btrfs_root),
GFP_NOFS);
struct btrfs_root *dev_root = kmalloc(sizeof(struct btrfs_root),
GFP_NOFS);
int ret;
int err = -EIO;
struct btrfs_super_block *disk_super;
......@@ -657,6 +696,12 @@ struct btrfs_root *open_ctree(struct super_block *sb)
fs_info->last_trans_committed = 0;
fs_info->tree_root = tree_root;
fs_info->extent_root = extent_root;
fs_info->chunk_root = chunk_root;
fs_info->dev_root = dev_root;
INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots);
INIT_LIST_HEAD(&fs_info->devices);
btrfs_mapping_init(&fs_info->mapping_tree);
fs_info->last_device = &fs_info->devices;
fs_info->sb = sb;
fs_info->throttles = 0;
fs_info->mount_opt = 0;
......@@ -714,12 +759,12 @@ struct btrfs_root *open_ctree(struct super_block *sb)
goto fail_iput;
}
#endif
__setup_root(512, 512, 512, 512, tree_root,
__setup_root(4096, 4096, 4096, 4096, tree_root,
fs_info, BTRFS_ROOT_TREE_OBJECTID);
fs_info->sb_buffer = read_tree_block(tree_root,
BTRFS_SUPER_INFO_OFFSET,
512);
4096);
if (!fs_info->sb_buffer)
goto fail_iput;
......@@ -730,6 +775,7 @@ struct btrfs_root *open_ctree(struct super_block *sb)
read_extent_buffer(fs_info->sb_buffer, fs_info->fsid,
(unsigned long)btrfs_super_fsid(fs_info->sb_buffer),
BTRFS_FSID_SIZE);
disk_super = &fs_info->super_copy;
if (!btrfs_super_root(disk_super))
goto fail_sb_buffer;
......@@ -753,23 +799,47 @@ struct btrfs_root *open_ctree(struct super_block *sb)
goto fail_sb_buffer;
}
mutex_lock(&fs_info->fs_mutex);
ret = btrfs_read_sys_array(tree_root);
BUG_ON(ret);
blocksize = btrfs_level_size(tree_root,
btrfs_super_chunk_root_level(disk_super));
__setup_root(nodesize, leafsize, sectorsize, stripesize,
chunk_root, fs_info, BTRFS_CHUNK_TREE_OBJECTID);
chunk_root->node = read_tree_block(chunk_root,
btrfs_super_chunk_root(disk_super),
blocksize);
BUG_ON(!chunk_root->node);
ret = btrfs_read_chunk_tree(chunk_root);
BUG_ON(ret);
blocksize = btrfs_level_size(tree_root,
btrfs_super_root_level(disk_super));
tree_root->node = read_tree_block(tree_root,
btrfs_super_root(disk_super),
blocksize);
if (!tree_root->node)
goto fail_sb_buffer;
mutex_lock(&fs_info->fs_mutex);
ret = find_and_setup_root(tree_root, fs_info,
BTRFS_EXTENT_TREE_OBJECTID, extent_root);
if (ret) {
mutex_unlock(&fs_info->fs_mutex);
if (ret)
goto fail_tree_root;
}
extent_root->track_dirty = 1;
ret = find_and_setup_root(tree_root, fs_info,
BTRFS_DEV_TREE_OBJECTID, dev_root);
dev_root->track_dirty = 1;
if (ret)
goto fail_extent_root;
btrfs_read_block_groups(extent_root);
......@@ -777,7 +847,10 @@ struct btrfs_root *open_ctree(struct super_block *sb)
mutex_unlock(&fs_info->fs_mutex);
return tree_root;
fail_extent_root:
free_extent_buffer(extent_root->node);
fail_tree_root:
mutex_unlock(&fs_info->fs_mutex);
free_extent_buffer(tree_root->node);
fail_sb_buffer:
free_extent_buffer(fs_info->sb_buffer);
......@@ -874,6 +947,12 @@ int close_ctree(struct btrfs_root *root)
if (fs_info->tree_root->node)
free_extent_buffer(fs_info->tree_root->node);
if (root->fs_info->chunk_root->node);
free_extent_buffer(root->fs_info->chunk_root->node);
if (root->fs_info->dev_root->node);
free_extent_buffer(root->fs_info->dev_root->node);
free_extent_buffer(fs_info->sb_buffer);
btrfs_free_block_groups(root->fs_info);
......@@ -901,8 +980,13 @@ int close_ctree(struct btrfs_root *root)
kfree(hasher);
}
#endif
close_all_devices(fs_info);
btrfs_mapping_tree_free(&fs_info->mapping_tree);
kfree(fs_info->extent_root);
kfree(fs_info->tree_root);
kfree(fs_info->chunk_root);
kfree(fs_info->dev_root);
return 0;
}
......@@ -1016,4 +1100,5 @@ int btrfs_read_buffer(struct extent_buffer *buf)
static struct extent_io_ops btree_extent_io_ops = {
.writepage_io_hook = btree_writepage_io_hook,
.submit_bio_hook = btree_submit_bio_hook,
};
......@@ -20,6 +20,7 @@
#define __DISKIO__
#define BTRFS_SUPER_INFO_OFFSET (16 * 1024)
struct btrfs_device;
struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
u32 blocksize);
......@@ -65,4 +66,5 @@ int btrfs_read_buffer(struct extent_buffer *buf);
u32 btrfs_csum_data(struct btrfs_root *root, char *data, u32 seed, size_t len);
void btrfs_csum_final(u32 crc, char *result);
void btrfs_throttle(struct btrfs_root *root);
int btrfs_open_device(struct btrfs_device *dev);
#endif
This diff is collapsed.
......@@ -1706,9 +1706,9 @@ static int submit_one_bio(int rw, struct bio *bio)
WARN_ON(1);
}
if (tree->ops && tree->ops->submit_bio_hook)
tree->ops->submit_bio_hook(rw, bio);
submit_bio(rw, bio);
tree->ops->submit_bio_hook(page->mapping->host, rw, bio);
else
submit_bio(rw, bio);
if (bio_flagged(bio, BIO_EOPNOTSUPP))
ret = -EOPNOTSUPP;
bio_put(bio);
......
......@@ -28,7 +28,7 @@ struct extent_state;
struct extent_io_ops {
int (*fill_delalloc)(struct inode *inode, u64 start, u64 end);
int (*writepage_io_hook)(struct page *page, u64 start, u64 end);
int (*submit_bio_hook)(int rw, struct bio *bio);
int (*submit_bio_hook)(struct inode *inode, int rw, struct bio *bio);
int (*readpage_io_hook)(struct page *page, u64 start, u64 end);
int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end,
struct extent_state *state);
......
......@@ -40,6 +40,7 @@
#include "btrfs_inode.h"
#include "ioctl.h"
#include "print-tree.h"
#include "volumes.h"
struct btrfs_iget_args {
u64 ino;
......@@ -295,20 +296,20 @@ int btrfs_clear_bit_hook(struct inode *inode, u64 start, u64 end,
return 0;
}
int btrfs_submit_bio_hook(int rw, struct bio *bio)
int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio)
{
struct bio_vec *bvec = bio->bi_io_vec;
struct inode *inode = bvec->bv_page->mapping->host;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_trans_handle *trans;
int ret = 0;
if (rw != WRITE)
return 0;
if (rw != WRITE) {
goto mapit;
}
if (btrfs_test_opt(root, NODATASUM) ||
btrfs_test_flag(inode, NODATASUM))
return 0;
btrfs_test_flag(inode, NODATASUM)) {
goto mapit;
}
mutex_lock(&root->fs_info->fs_mutex);
trans = btrfs_start_transaction(root, 1);
......@@ -317,7 +318,8 @@ int btrfs_submit_bio_hook(int rw, struct bio *bio)
ret = btrfs_end_transaction(trans, root);
BUG_ON(ret);
mutex_unlock(&root->fs_info->fs_mutex);
return ret;
mapit:
return btrfs_map_bio(root, rw, bio);
}
int btrfs_readpage_io_hook(struct page *page, u64 start, u64 end)
......@@ -406,7 +408,7 @@ void btrfs_read_locked_inode(struct inode *inode)
struct btrfs_path *path;
struct extent_buffer *leaf;
struct btrfs_inode_item *inode_item;
struct btrfs_inode_timespec *tspec;
struct btrfs_timespec *tspec;
struct btrfs_root *root = BTRFS_I(inode)->root;
struct btrfs_key location;
u64 alloc_group_block;
......@@ -455,7 +457,8 @@ void btrfs_read_locked_inode(struct inode *inode)
BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
if (!BTRFS_I(inode)->block_group) {
BTRFS_I(inode)->block_group = btrfs_find_block_group(root,
NULL, 0, 0, 0);
NULL, 0,
BTRFS_BLOCK_GROUP_METADATA, 0);
}
btrfs_free_path(path);
inode_item = NULL;
......@@ -1550,7 +1553,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
owner = 0;
else
owner = 1;
group = btrfs_find_block_group(root, group, 0, 0, owner);
group = btrfs_find_block_group(root, group, 0,
BTRFS_BLOCK_GROUP_METADATA, owner);
BTRFS_I(inode)->block_group = group;
BTRFS_I(inode)->flags = 0;
......
......@@ -20,6 +20,40 @@
#include "disk-io.h"
#include "print-tree.h"
static void print_chunk(struct extent_buffer *eb, struct btrfs_chunk *chunk)
{
int num_stripes = btrfs_chunk_num_stripes(eb, chunk);
int i;
printk("\t\tchunk owner %llu type %llu num_stripes %d\n",
(unsigned long long)btrfs_chunk_owner(eb, chunk),
(unsigned long long)btrfs_chunk_type(eb, chunk),
num_stripes);
for (i = 0 ; i < num_stripes ; i++) {
printk("\t\t\tstripe %d devid %llu offset %llu\n", i,
(unsigned long long)btrfs_stripe_devid_nr(eb, chunk, i),
(unsigned long long)btrfs_stripe_offset_nr(eb, chunk, i));
}
}
static void print_dev_item(struct extent_buffer *eb,
struct btrfs_dev_item *dev_item)
{
char *name;
int name_len;
name_len = btrfs_device_name_len(eb, dev_item);
name = kmalloc(name_len, GFP_NOFS);
if (name) {
read_extent_buffer(eb, name,
(unsigned long)btrfs_device_name(dev_item),
name_len);
}
printk("\t\tdev item name %.*s devid %llu "
"total_bytes %llu bytes used %Lu\n", name_len, name,
(unsigned long long)btrfs_device_id(eb, dev_item),
(unsigned long long)btrfs_device_total_bytes(eb, dev_item),
(unsigned long long)btrfs_device_bytes_used(eb, dev_item));
kfree(name);
}
void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
{
int i;
......@@ -34,6 +68,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
struct btrfs_key key;
struct btrfs_key found_key;
struct btrfs_extent_ref *ref;
struct btrfs_dev_extent *dev_extent;
u32 type;
printk("leaf %llu total ptrs %d free space %d\n",
......@@ -106,6 +141,19 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
printk("\t\tblock group used %llu\n",
(unsigned long long)btrfs_disk_block_group_used(l, bi));
break;
case BTRFS_CHUNK_ITEM_KEY:
print_chunk(l, btrfs_item_ptr(l, i, struct btrfs_chunk));
break;
case BTRFS_DEV_ITEM_KEY:
print_dev_item(l, btrfs_item_ptr(l, i,
struct btrfs_dev_item));
break;
case BTRFS_DEV_EXTENT_KEY:
dev_extent = btrfs_item_ptr(l, i,
struct btrfs_dev_extent);
printk("\t\tdev extent owner %llu length %llu\n",
(unsigned long long)btrfs_dev_extent_owner(l, dev_extent),
(unsigned long long)btrfs_dev_extent_length(l, dev_extent));
};
}
}
......
......@@ -198,29 +198,42 @@ int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
return werr;
}
int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
static int update_cowonly_root(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
int ret;
u64 old_extent_block;
struct btrfs_fs_info *fs_info = root->fs_info;
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_root *extent_root = fs_info->extent_root;
u64 old_root_bytenr;
struct btrfs_root *tree_root = root->fs_info->tree_root;
btrfs_write_dirty_block_groups(trans, extent_root);
btrfs_write_dirty_block_groups(trans, root);
while(1) {
old_extent_block = btrfs_root_bytenr(&extent_root->root_item);
if (old_extent_block == extent_root->node->start)
old_root_bytenr = btrfs_root_bytenr(&root->root_item);
if (old_root_bytenr == root->node->start)
break;
btrfs_set_root_bytenr(&extent_root->root_item,
extent_root->node->start);
btrfs_set_root_level(&extent_root->root_item,
btrfs_header_level(extent_root->node));
btrfs_set_root_bytenr(&root->root_item,
root->node->start);
btrfs_set_root_level(&root->root_item,
btrfs_header_level(root->node));
ret = btrfs_update_root(trans, tree_root,
&extent_root->root_key,
&extent_root->root_item);
&root->root_key,
&root->root_item);
BUG_ON(ret);
btrfs_write_dirty_block_groups(trans, extent_root);
btrfs_write_dirty_block_groups(trans, root);
}
return 0;
}
int btrfs_commit_tree_roots(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
struct btrfs_fs_info *fs_info = root->fs_info;
struct list_head *next;
while(!list_empty(&fs_info->dirty_cowonly_roots)) {
next = fs_info->dirty_cowonly_roots.next;
list_del_init(next);
root = list_entry(next, struct btrfs_root, dirty_list);
update_cowonly_root(trans, root);
}
return 0;
}
......@@ -616,6 +629,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
unsigned long timeout = 1;
struct btrfs_transaction *cur_trans;
struct btrfs_transaction *prev_trans = NULL;
struct btrfs_root *chunk_root = root->fs_info->chunk_root;
struct list_head dirty_fs_roots;
struct extent_io_tree *pinned_copy;
DEFINE_WAIT(wait);
......@@ -714,6 +728,10 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
btrfs_set_super_root_level(&root->fs_info->super_copy,
btrfs_header_level(root->fs_info->tree_root->node));
btrfs_set_super_chunk_root(&root->fs_info->super_copy,
chunk_root->node->start);
btrfs_set_super_chunk_root_level(&root->fs_info->super_copy,
btrfs_header_level(chunk_root->node));
write_extent_buffer(root->fs_info->sb_buffer,
&root->fs_info->super_copy, 0,
sizeof(root->fs_info->super_copy));
......
This diff is collapsed.
/*
* Copyright (C) 2007 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.
*/
#ifndef __BTRFS_VOLUMES_
#define __BTRFS_VOLUMES_
struct btrfs_device {
struct list_head dev_list;
struct btrfs_root *dev_root;
struct btrfs_key dev_key;
struct block_device *bdev;
/* the internal btrfs device id */
u64 devid;
/* size of the device */
u64 total_bytes;
/* bytes used */
u64 bytes_used;
/* optimal io alignment for this device */
u32 io_align;
/* optimal io width for this device */
u32 io_width;
/* minimal io size for this device */
u32 sector_size;
/* the kernel device number */
u64 rdev;
/* type and info about this device */
u64 type;
/* partition number, 0 for whole dev */
int partition;
/* length of the name data at the end of the item */
int name_len;
/* physical drive uuid (or lvm uuid) */
u8 uuid[BTRFS_DEV_UUID_SIZE];
char *name;
};
int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
struct btrfs_device *device,
u64 owner, u64 num_bytes, u64 *start);
int btrfs_map_block(struct btrfs_mapping_tree *map_tree,
u64 logical, u64 *phys, u64 *length,
struct btrfs_device **dev);
int btrfs_read_sys_array(struct btrfs_root *root);
int btrfs_read_chunk_tree(struct btrfs_root *root);
int btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
struct btrfs_root *extent_root, u64 *start,
u64 *num_bytes, u32 type);
void btrfs_mapping_init(struct btrfs_mapping_tree *tree);
void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree);
int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment