2007-03-22 19:13:20 +03:00
# include <linux/module.h>
# include <linux/fs.h>
2007-02-02 17:18:22 +03:00
# include "ctree.h"
# include "disk-io.h"
2007-03-16 23:20:31 +03:00
# include "transaction.h"
2007-02-02 17:18:22 +03:00
2007-03-22 19:13:20 +03:00
static int check_tree_block ( struct btrfs_root * root , struct buffer_head * buf )
2007-02-02 17:18:22 +03:00
{
2007-03-22 19:13:20 +03:00
struct btrfs_node * node = btrfs_buffer_node ( buf ) ;
if ( buf - > b_blocknr ! = btrfs_header_blocknr ( & node - > header ) )
2007-02-23 16:38:36 +03:00
BUG ( ) ;
2007-03-22 19:13:20 +03:00
if ( root - > node & & btrfs_header_parentid ( & node - > header ) ! =
2007-03-23 18:00:45 +03:00
btrfs_header_parentid ( btrfs_buffer_header ( root - > node ) ) ) {
2007-03-23 22:56:19 +03:00
BUG ( ) ;
2007-03-23 18:00:45 +03:00
}
2007-02-23 16:38:36 +03:00
return 0 ;
2007-02-02 17:18:22 +03:00
}
2007-03-22 19:13:20 +03:00
struct buffer_head * alloc_tree_block ( struct btrfs_root * root , u64 blocknr )
2007-03-02 02:59:40 +03:00
{
2007-03-22 19:13:20 +03:00
return sb_getblk ( root - > fs_info - > sb , blocknr ) ;
2007-03-02 02:59:40 +03:00
}
2007-03-22 19:13:20 +03:00
struct buffer_head * find_tree_block ( struct btrfs_root * root , u64 blocknr )
2007-02-02 17:18:22 +03:00
{
2007-03-22 19:13:20 +03:00
return sb_getblk ( root - > fs_info - > sb , blocknr ) ;
2007-02-02 17:18:22 +03:00
}
2007-03-22 19:13:20 +03:00
struct buffer_head * read_tree_block ( struct btrfs_root * root , u64 blocknr )
2007-02-02 17:18:22 +03:00
{
2007-03-22 19:13:20 +03:00
struct buffer_head * buf = sb_bread ( root - > fs_info - > sb , blocknr ) ;
2007-02-02 17:18:22 +03:00
2007-03-22 19:13:20 +03:00
if ( ! buf )
return buf ;
2007-02-23 16:38:36 +03:00
if ( check_tree_block ( root , buf ) )
2007-02-22 01:04:57 +03:00
BUG ( ) ;
2007-02-02 17:18:22 +03:00
return buf ;
}
2007-03-16 23:20:31 +03:00
int dirty_tree_block ( struct btrfs_trans_handle * trans , struct btrfs_root * root ,
2007-03-22 19:13:20 +03:00
struct buffer_head * buf )
2007-03-02 02:59:40 +03:00
{
2007-03-22 19:13:20 +03:00
mark_buffer_dirty ( buf ) ;
2007-03-02 02:59:40 +03:00
return 0 ;
}
2007-03-16 23:20:31 +03:00
int clean_tree_block ( struct btrfs_trans_handle * trans , struct btrfs_root * root ,
2007-03-22 19:13:20 +03:00
struct buffer_head * buf )
2007-03-02 02:59:40 +03:00
{
2007-03-22 19:13:20 +03:00
clear_buffer_dirty ( buf ) ;
2007-03-02 02:59:40 +03:00
return 0 ;
}
2007-03-14 21:14:43 +03:00
static int __setup_root ( struct btrfs_super_block * super ,
2007-03-20 21:38:32 +03:00
struct btrfs_root * root ,
struct btrfs_fs_info * fs_info ,
2007-03-22 19:13:20 +03:00
u64 objectid )
2007-02-21 00:40:44 +03:00
{
2007-02-22 01:04:57 +03:00
root - > node = NULL ;
2007-03-07 04:08:01 +03:00
root - > commit_root = NULL ;
2007-03-14 21:14:43 +03:00
root - > blocksize = btrfs_super_blocksize ( super ) ;
root - > ref_cows = 0 ;
2007-03-20 21:38:32 +03:00
root - > fs_info = fs_info ;
2007-03-13 23:47:54 +03:00
memset ( & root - > root_key , 0 , sizeof ( root - > root_key ) ) ;
memset ( & root - > root_item , 0 , sizeof ( root - > root_item ) ) ;
return 0 ;
}
2007-03-14 21:14:43 +03:00
static int find_and_setup_root ( struct btrfs_super_block * super ,
2007-03-20 21:38:32 +03:00
struct btrfs_root * tree_root ,
struct btrfs_fs_info * fs_info ,
u64 objectid ,
2007-03-22 19:13:20 +03:00
struct btrfs_root * root )
2007-03-13 23:47:54 +03:00
{
int ret ;
2007-03-22 19:13:20 +03:00
__setup_root ( super , root , fs_info , objectid ) ;
2007-03-13 23:47:54 +03:00
ret = btrfs_find_last_root ( tree_root , objectid ,
& root - > root_item , & root - > root_key ) ;
BUG_ON ( ret ) ;
root - > node = read_tree_block ( root ,
btrfs_root_blocknr ( & root - > root_item ) ) ;
BUG_ON ( ! root - > node ) ;
2007-02-21 00:40:44 +03:00
return 0 ;
}
2007-03-22 19:13:20 +03:00
struct btrfs_root * open_ctree ( struct super_block * sb ,
struct buffer_head * sb_buffer ,
struct btrfs_super_block * disk_super )
2007-03-21 18:12:56 +03:00
{
2007-03-22 19:13:20 +03:00
struct btrfs_root * root = kmalloc ( sizeof ( struct btrfs_root ) ,
GFP_NOFS ) ;
struct btrfs_root * extent_root = kmalloc ( sizeof ( struct btrfs_root ) ,
GFP_NOFS ) ;
struct btrfs_root * tree_root = kmalloc ( sizeof ( struct btrfs_root ) ,
GFP_NOFS ) ;
struct btrfs_root * inode_root = kmalloc ( sizeof ( struct btrfs_root ) ,
GFP_NOFS ) ;
struct btrfs_fs_info * fs_info = kmalloc ( sizeof ( * fs_info ) ,
GFP_NOFS ) ;
2007-02-02 17:18:22 +03:00
int ret ;
2007-03-22 19:13:20 +03:00
/* FIXME: don't be stupid */
if ( ! btrfs_super_root ( disk_super ) )
return NULL ;
2007-03-20 21:38:32 +03:00
INIT_RADIX_TREE ( & fs_info - > pinned_radix , GFP_KERNEL ) ;
fs_info - > running_transaction = NULL ;
fs_info - > fs_root = root ;
fs_info - > tree_root = tree_root ;
fs_info - > extent_root = extent_root ;
fs_info - > inode_root = inode_root ;
fs_info - > last_inode_alloc = 0 ;
fs_info - > last_inode_alloc_dirid = 0 ;
2007-03-22 19:13:20 +03:00
fs_info - > disk_super = disk_super ;
fs_info - > sb_buffer = sb_buffer ;
fs_info - > sb = sb ;
2007-03-22 22:59:16 +03:00
mutex_init ( & fs_info - > trans_mutex ) ;
2007-03-24 02:47:49 +03:00
mutex_init ( & fs_info - > fs_mutex ) ;
2007-03-20 21:38:32 +03:00
memset ( & fs_info - > current_insert , 0 , sizeof ( fs_info - > current_insert ) ) ;
memset ( & fs_info - > last_insert , 0 , sizeof ( fs_info - > last_insert ) ) ;
2007-03-13 23:47:54 +03:00
2007-03-22 19:13:20 +03:00
__setup_root ( disk_super , tree_root , fs_info , BTRFS_ROOT_TREE_OBJECTID ) ;
tree_root - > node = read_tree_block ( tree_root ,
btrfs_super_root ( disk_super ) ) ;
2007-03-13 23:47:54 +03:00
BUG_ON ( ! tree_root - > node ) ;
2007-03-22 19:13:20 +03:00
ret = find_and_setup_root ( disk_super , tree_root , fs_info ,
BTRFS_EXTENT_TREE_OBJECTID , extent_root ) ;
2007-03-13 23:47:54 +03:00
BUG_ON ( ret ) ;
2007-03-22 19:13:20 +03:00
ret = find_and_setup_root ( disk_super , tree_root , fs_info ,
BTRFS_INODE_MAP_OBJECTID , inode_root ) ;
2007-03-20 21:38:32 +03:00
BUG_ON ( ret ) ;
2007-03-22 19:13:20 +03:00
ret = find_and_setup_root ( disk_super , tree_root , fs_info ,
BTRFS_FS_TREE_OBJECTID , root ) ;
2007-03-13 23:47:54 +03:00
BUG_ON ( ret ) ;
2007-03-07 04:08:01 +03:00
root - > commit_root = root - > node ;
2007-03-22 19:13:20 +03:00
get_bh ( root - > node ) ;
2007-03-13 23:47:54 +03:00
root - > ref_cows = 1 ;
2007-03-20 22:57:25 +03:00
root - > fs_info - > generation = root - > root_key . offset + 1 ;
2007-02-02 17:18:22 +03:00
return root ;
}
2007-03-16 23:20:31 +03:00
int write_ctree_super ( struct btrfs_trans_handle * trans , struct btrfs_root
2007-03-22 22:59:16 +03:00
* root )
2007-02-02 17:18:22 +03:00
{
2007-03-23 17:01:08 +03:00
struct buffer_head * bh = root - > fs_info - > sb_buffer ;
btrfs_set_super_root ( root - > fs_info - > disk_super ,
root - > fs_info - > tree_root - > node - > b_blocknr ) ;
lock_buffer ( bh ) ;
clear_buffer_dirty ( bh ) ;
bh - > b_end_io = end_buffer_write_sync ;
get_bh ( bh ) ;
submit_bh ( WRITE , bh ) ;
wait_on_buffer ( bh ) ;
if ( ! buffer_uptodate ( bh ) ) {
WARN_ON ( 1 ) ;
return - EIO ;
2007-02-22 01:04:57 +03:00
}
return 0 ;
}
2007-03-22 19:13:20 +03:00
int close_ctree ( struct btrfs_root * root )
2007-02-22 01:04:57 +03:00
{
2007-03-13 23:47:54 +03:00
int ret ;
2007-03-16 23:20:31 +03:00
struct btrfs_trans_handle * trans ;
2007-03-22 22:59:16 +03:00
trans = btrfs_start_transaction ( root , 1 ) ;
btrfs_commit_transaction ( trans , root ) ;
/* run commit again to drop the original snapshot */
trans = btrfs_start_transaction ( root , 1 ) ;
btrfs_commit_transaction ( trans , root ) ;
ret = btrfs_write_and_wait_transaction ( NULL , root ) ;
2007-03-13 23:47:54 +03:00
BUG_ON ( ret ) ;
2007-03-22 22:59:16 +03:00
write_ctree_super ( NULL , root ) ;
2007-03-02 02:59:40 +03:00
2007-02-22 01:04:57 +03:00
if ( root - > node )
2007-03-13 17:46:10 +03:00
btrfs_block_release ( root , root - > node ) ;
2007-03-20 21:38:32 +03:00
if ( root - > fs_info - > extent_root - > node )
btrfs_block_release ( root - > fs_info - > extent_root ,
root - > fs_info - > extent_root - > node ) ;
if ( root - > fs_info - > inode_root - > node )
btrfs_block_release ( root - > fs_info - > inode_root ,
root - > fs_info - > inode_root - > node ) ;
if ( root - > fs_info - > tree_root - > node )
btrfs_block_release ( root - > fs_info - > tree_root ,
root - > fs_info - > tree_root - > node ) ;
2007-03-13 17:46:10 +03:00
btrfs_block_release ( root , root - > commit_root ) ;
2007-03-22 19:13:20 +03:00
btrfs_block_release ( root , root - > fs_info - > sb_buffer ) ;
kfree ( root - > fs_info - > extent_root ) ;
kfree ( root - > fs_info - > inode_root ) ;
kfree ( root - > fs_info - > tree_root ) ;
kfree ( root - > fs_info ) ;
kfree ( root ) ;
2007-02-02 17:18:22 +03:00
return 0 ;
}
2007-03-22 19:13:20 +03:00
void btrfs_block_release ( struct btrfs_root * root , struct buffer_head * buf )
2007-02-02 17:18:22 +03:00
{
2007-03-22 19:13:20 +03:00
brelse ( buf ) ;
2007-02-02 17:18:22 +03:00
}