2007-06-12 09:07:21 -04:00
/*
* 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 .
*/
2007-03-13 16:47:54 -04:00
# include "ctree.h"
2007-06-22 14:16:25 -04:00
# include "transaction.h"
2007-03-13 16:47:54 -04:00
# include "disk-io.h"
# include "print-tree.h"
2008-05-08 13:26:18 -04:00
/*
* returns 0 on finding something , 1 if no more roots are there
* and < 0 on error
*/
int btrfs_search_root ( struct btrfs_root * root , u64 search_start ,
u64 * found_objectid )
{
struct btrfs_path * path ;
struct btrfs_key search_key ;
int ret ;
root = root - > fs_info - > tree_root ;
search_key . objectid = search_start ;
search_key . type = ( u8 ) - 1 ;
search_key . offset = ( u64 ) - 1 ;
path = btrfs_alloc_path ( ) ;
BUG_ON ( ! path ) ;
again :
ret = btrfs_search_slot ( NULL , root , & search_key , path , 0 , 0 ) ;
if ( ret < 0 )
goto out ;
if ( ret = = 0 ) {
ret = 1 ;
goto out ;
}
if ( path - > slots [ 0 ] > = btrfs_header_nritems ( path - > nodes [ 0 ] ) ) {
ret = btrfs_next_leaf ( root , path ) ;
if ( ret )
goto out ;
}
btrfs_item_key_to_cpu ( path - > nodes [ 0 ] , & search_key , path - > slots [ 0 ] ) ;
if ( search_key . type ! = BTRFS_ROOT_ITEM_KEY ) {
search_key . offset + + ;
btrfs_release_path ( root , path ) ;
goto again ;
}
ret = 0 ;
* found_objectid = search_key . objectid ;
out :
btrfs_free_path ( path ) ;
return ret ;
}
2007-03-13 16:47:54 -04:00
int btrfs_find_last_root ( struct btrfs_root * root , u64 objectid ,
struct btrfs_root_item * item , struct btrfs_key * key )
{
2007-04-02 11:20:42 -04:00
struct btrfs_path * path ;
2007-03-13 16:47:54 -04:00
struct btrfs_key search_key ;
2007-10-15 16:14:19 -04:00
struct btrfs_key found_key ;
struct extent_buffer * l ;
2007-03-13 16:47:54 -04:00
int ret ;
int slot ;
search_key . objectid = objectid ;
2007-10-15 16:14:19 -04:00
search_key . type = ( u8 ) - 1 ;
2007-06-22 14:16:25 -04:00
search_key . offset = ( u64 ) - 1 ;
2007-03-13 16:47:54 -04:00
2007-04-02 11:20:42 -04:00
path = btrfs_alloc_path ( ) ;
BUG_ON ( ! path ) ;
ret = btrfs_search_slot ( NULL , root , & search_key , path , 0 , 0 ) ;
2007-03-13 16:47:54 -04:00
if ( ret < 0 )
goto out ;
2007-10-15 16:14:19 -04:00
2007-03-13 16:47:54 -04:00
BUG_ON ( ret = = 0 ) ;
2007-10-15 16:14:19 -04:00
l = path - > nodes [ 0 ] ;
2007-04-02 11:20:42 -04:00
BUG_ON ( path - > slots [ 0 ] = = 0 ) ;
slot = path - > slots [ 0 ] - 1 ;
2007-10-15 16:14:19 -04:00
btrfs_item_key_to_cpu ( l , & found_key , slot ) ;
if ( found_key . objectid ! = objectid ) {
2007-03-13 16:47:54 -04:00
ret = 1 ;
goto out ;
}
2007-10-15 16:14:19 -04:00
read_extent_buffer ( l , item , btrfs_item_ptr_offset ( l , slot ) ,
sizeof ( * item ) ) ;
memcpy ( key , & found_key , sizeof ( found_key ) ) ;
2007-03-13 16:47:54 -04:00
ret = 0 ;
out :
2007-04-02 11:20:42 -04:00
btrfs_free_path ( path ) ;
2007-03-13 16:47:54 -04:00
return ret ;
}
2007-03-16 16:20:31 -04:00
int btrfs_update_root ( struct btrfs_trans_handle * trans , struct btrfs_root
* root , struct btrfs_key * key , struct btrfs_root_item
* item )
2007-03-13 16:47:54 -04:00
{
2007-04-02 11:20:42 -04:00
struct btrfs_path * path ;
2007-10-15 16:14:19 -04:00
struct extent_buffer * l ;
2007-03-13 16:47:54 -04:00
int ret ;
int slot ;
2007-10-15 16:14:19 -04:00
unsigned long ptr ;
2007-03-13 16:47:54 -04:00
2007-04-02 11:20:42 -04:00
path = btrfs_alloc_path ( ) ;
BUG_ON ( ! path ) ;
ret = btrfs_search_slot ( trans , root , key , path , 0 , 1 ) ;
2007-03-13 16:47:54 -04:00
if ( ret < 0 )
goto out ;
2008-01-03 14:51:00 -05:00
if ( ret ! = 0 ) {
btrfs_print_leaf ( root , path - > nodes [ 0 ] ) ;
printk ( " unable to update root key %Lu %u %Lu \n " ,
key - > objectid , key - > type , key - > offset ) ;
BUG_ON ( 1 ) ;
}
2007-10-15 16:14:19 -04:00
l = path - > nodes [ 0 ] ;
2007-04-02 11:20:42 -04:00
slot = path - > slots [ 0 ] ;
2007-10-15 16:14:19 -04:00
ptr = btrfs_item_ptr_offset ( l , slot ) ;
write_extent_buffer ( l , item , ptr , sizeof ( * item ) ) ;
2007-04-02 11:20:42 -04:00
btrfs_mark_buffer_dirty ( path - > nodes [ 0 ] ) ;
2007-03-13 16:47:54 -04:00
out :
2007-04-02 11:20:42 -04:00
btrfs_release_path ( root , path ) ;
btrfs_free_path ( path ) ;
2007-03-13 16:47:54 -04:00
return ret ;
}
2007-03-16 16:20:31 -04:00
int btrfs_insert_root ( struct btrfs_trans_handle * trans , struct btrfs_root
* root , struct btrfs_key * key , struct btrfs_root_item
* item )
2007-03-13 16:47:54 -04:00
{
int ret ;
2007-03-16 16:20:31 -04:00
ret = btrfs_insert_item ( trans , root , key , item , sizeof ( * item ) ) ;
2007-03-13 16:47:54 -04:00
return ret ;
}
2007-09-11 11:15:39 -04:00
int btrfs_find_dead_roots ( struct btrfs_root * root , u64 objectid ,
struct btrfs_root * latest )
2007-06-22 14:16:25 -04:00
{
struct btrfs_root * dead_root ;
struct btrfs_item * item ;
struct btrfs_root_item * ri ;
struct btrfs_key key ;
2008-06-26 10:34:20 -04:00
struct btrfs_key found_key ;
2007-06-22 14:16:25 -04:00
struct btrfs_path * path ;
int ret ;
u32 nritems ;
2007-10-15 16:14:19 -04:00
struct extent_buffer * leaf ;
2007-06-22 14:16:25 -04:00
int slot ;
2007-09-11 11:15:39 -04:00
key . objectid = objectid ;
2007-06-22 14:16:25 -04:00
btrfs_set_key_type ( & key , BTRFS_ROOT_ITEM_KEY ) ;
key . offset = 0 ;
path = btrfs_alloc_path ( ) ;
if ( ! path )
return - ENOMEM ;
2008-06-26 10:34:20 -04:00
again :
2007-06-22 14:16:25 -04:00
ret = btrfs_search_slot ( NULL , root , & key , path , 0 , 0 ) ;
if ( ret < 0 )
goto err ;
while ( 1 ) {
2007-10-15 16:14:19 -04:00
leaf = path - > nodes [ 0 ] ;
nritems = btrfs_header_nritems ( leaf ) ;
2007-06-22 14:16:25 -04:00
slot = path - > slots [ 0 ] ;
if ( slot > = nritems ) {
ret = btrfs_next_leaf ( root , path ) ;
if ( ret )
break ;
2007-10-15 16:14:19 -04:00
leaf = path - > nodes [ 0 ] ;
nritems = btrfs_header_nritems ( leaf ) ;
2007-06-22 14:16:25 -04:00
slot = path - > slots [ 0 ] ;
}
2007-10-15 16:14:19 -04:00
item = btrfs_item_nr ( leaf , slot ) ;
btrfs_item_key_to_cpu ( leaf , & key , slot ) ;
2007-06-22 14:16:25 -04:00
if ( btrfs_key_type ( & key ) ! = BTRFS_ROOT_ITEM_KEY )
goto next ;
2007-09-11 11:15:39 -04:00
if ( key . objectid < objectid )
goto next ;
if ( key . objectid > objectid )
break ;
2007-06-22 14:16:25 -04:00
ri = btrfs_item_ptr ( leaf , slot , struct btrfs_root_item ) ;
2007-10-15 16:14:19 -04:00
if ( btrfs_disk_root_refs ( leaf , ri ) ! = 0 )
2007-06-22 14:16:25 -04:00
goto next ;
2007-09-11 11:15:39 -04:00
2008-06-26 10:34:20 -04:00
memcpy ( & found_key , & key , sizeof ( key ) ) ;
key . offset + + ;
btrfs_release_path ( root , path ) ;
dead_root = btrfs_read_fs_root_no_radix ( root - > fs_info ,
& found_key ) ;
2007-07-11 10:03:27 -04:00
if ( IS_ERR ( dead_root ) ) {
ret = PTR_ERR ( dead_root ) ;
2007-06-22 14:16:25 -04:00
goto err ;
}
2007-09-11 11:15:39 -04:00
2008-08-04 23:23:47 -04:00
ret = btrfs_add_dead_root ( dead_root , latest ) ;
2007-06-22 14:16:25 -04:00
if ( ret )
goto err ;
2008-06-26 10:34:20 -04:00
goto again ;
2007-06-22 14:16:25 -04:00
next :
slot + + ;
path - > slots [ 0 ] + + ;
}
ret = 0 ;
err :
btrfs_free_path ( path ) ;
return ret ;
}
2007-03-16 16:20:31 -04:00
int btrfs_del_root ( struct btrfs_trans_handle * trans , struct btrfs_root * root ,
struct btrfs_key * key )
2007-03-13 16:47:54 -04:00
{
2007-04-02 11:20:42 -04:00
struct btrfs_path * path ;
2007-03-13 16:47:54 -04:00
int ret ;
2007-04-10 09:27:04 -04:00
u32 refs ;
struct btrfs_root_item * ri ;
2007-10-15 16:14:19 -04:00
struct extent_buffer * leaf ;
2007-03-13 16:47:54 -04:00
2007-04-02 11:20:42 -04:00
path = btrfs_alloc_path ( ) ;
BUG_ON ( ! path ) ;
ret = btrfs_search_slot ( trans , root , key , path , - 1 , 1 ) ;
2007-03-13 16:47:54 -04:00
if ( ret < 0 )
goto out ;
2007-12-21 16:27:24 -05:00
if ( ret ) {
btrfs_print_leaf ( root , path - > nodes [ 0 ] ) ;
printk ( " failed to del %Lu %u %Lu \n " , key - > objectid , key - > type , key - > offset ) ;
}
2007-03-13 16:47:54 -04:00
BUG_ON ( ret ! = 0 ) ;
2007-10-15 16:14:19 -04:00
leaf = path - > nodes [ 0 ] ;
ri = btrfs_item_ptr ( leaf , path - > slots [ 0 ] , struct btrfs_root_item ) ;
2007-04-10 09:27:04 -04:00
2007-10-15 16:14:19 -04:00
refs = btrfs_disk_root_refs ( leaf , ri ) ;
2007-06-22 14:16:25 -04:00
BUG_ON ( refs ! = 0 ) ;
ret = btrfs_del_item ( trans , root , path ) ;
2007-03-13 16:47:54 -04:00
out :
2007-04-02 11:20:42 -04:00
btrfs_release_path ( root , path ) ;
btrfs_free_path ( path ) ;
2007-03-13 16:47:54 -04:00
return ret ;
}