@ -35,6 +35,7 @@
# include "free-space-cache.h"
# include "math.h"
# include "sysfs.h"
# include "qgroup.h"
# undef SCRAMBLE_DELAYED_REFS
@ -80,7 +81,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
u64 bytenr , u64 num_bytes , u64 parent ,
u64 root_objectid , u64 owner_objectid ,
u64 owner_offset , int refs_to_drop ,
struct btrfs_delayed_extent_op * extra_op ) ;
struct btrfs_delayed_extent_op * extra_op ,
int no_quota ) ;
static void __run_delayed_extent_op ( struct btrfs_delayed_extent_op * extent_op ,
struct extent_buffer * leaf ,
struct btrfs_extent_item * ei ) ;
@ -93,7 +95,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root * root ,
u64 parent , u64 root_objectid ,
u64 flags , struct btrfs_disk_key * key ,
int level , struct btrfs_key * ins ) ;
int level , struct btrfs_key * ins ,
int no_quota ) ;
static int do_chunk_alloc ( struct btrfs_trans_handle * trans ,
struct btrfs_root * extent_root , u64 flags ,
int force ) ;
@ -1270,7 +1273,7 @@ fail:
static noinline int remove_extent_data_ref ( struct btrfs_trans_handle * trans ,
struct btrfs_root * root ,
struct btrfs_path * path ,
int refs_to_drop )
int refs_to_drop , int * last_ref )
{
struct btrfs_key key ;
struct btrfs_extent_data_ref * ref1 = NULL ;
@ -1306,6 +1309,7 @@ static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans,
if ( num_refs = = 0 ) {
ret = btrfs_del_item ( trans , root , path ) ;
* last_ref = 1 ;
} else {
if ( key . type = = BTRFS_EXTENT_DATA_REF_KEY )
btrfs_set_extent_data_ref_count ( leaf , ref1 , num_refs ) ;
@ -1763,7 +1767,8 @@ void update_inline_extent_backref(struct btrfs_root *root,
struct btrfs_path * path ,
struct btrfs_extent_inline_ref * iref ,
int refs_to_mod ,
struct btrfs_delayed_extent_op * extent_op )
struct btrfs_delayed_extent_op * extent_op ,
int * last_ref )
{
struct extent_buffer * leaf ;
struct btrfs_extent_item * ei ;
@ -1807,6 +1812,7 @@ void update_inline_extent_backref(struct btrfs_root *root,
else
btrfs_set_shared_data_ref_count ( leaf , sref , refs ) ;
} else {
* last_ref = 1 ;
size = btrfs_extent_inline_ref_size ( type ) ;
item_size = btrfs_item_size_nr ( leaf , path - > slots [ 0 ] ) ;
ptr = ( unsigned long ) iref ;
@ -1838,7 +1844,7 @@ int insert_inline_extent_backref(struct btrfs_trans_handle *trans,
if ( ret = = 0 ) {
BUG_ON ( owner < BTRFS_FIRST_FREE_OBJECTID ) ;
update_inline_extent_backref ( root , path , iref ,
refs_to_add , extent_op ) ;
refs_to_add , extent_op , NULL ) ;
} else if ( ret = = - ENOENT ) {
setup_inline_extent_backref ( root , path , iref , parent ,
root_objectid , owner , offset ,
@ -1871,17 +1877,19 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
struct btrfs_root * root ,
struct btrfs_path * path ,
struct btrfs_extent_inline_ref * iref ,
int refs_to_drop , int is_data )
int refs_to_drop , int is_data , int * last_ref )
{
int ret = 0 ;
BUG_ON ( ! is_data & & refs_to_drop ! = 1 ) ;
if ( iref ) {
update_inline_extent_backref ( root , path , iref ,
- refs_to_drop , NULL ) ;
- refs_to_drop , NULL , last_ref ) ;
} else if ( is_data ) {
ret = remove_extent_data_ref ( trans , root , path , refs_to_drop ) ;
ret = remove_extent_data_ref ( trans , root , path , refs_to_drop ,
last_ref ) ;
} else {
* last_ref = 1 ;
ret = btrfs_del_item ( trans , root , path ) ;
}
return ret ;
@ -1945,7 +1953,8 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
int btrfs_inc_extent_ref ( struct btrfs_trans_handle * trans ,
struct btrfs_root * root ,
u64 bytenr , u64 num_bytes , u64 parent ,
u64 root_objectid , u64 owner , u64 offset , int for_cow )
u64 root_objectid , u64 owner , u64 offset ,
int no_quota )
{
int ret ;
struct btrfs_fs_info * fs_info = root - > fs_info ;
@ -1957,12 +1966,12 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
ret = btrfs_add_delayed_tree_ref ( fs_info , trans , bytenr ,
num_bytes ,
parent , root_objectid , ( int ) owner ,
BTRFS_ADD_DELAYED_REF , NULL , for_cow ) ;
BTRFS_ADD_DELAYED_REF , NULL , no_quota ) ;
} else {
ret = btrfs_add_delayed_data_ref ( fs_info , trans , bytenr ,
num_bytes ,
parent , root_objectid , owner , offset ,
BTRFS_ADD_DELAYED_REF , NULL , for_cow ) ;
BTRFS_ADD_DELAYED_REF , NULL , no_quota ) ;
}
return ret ;
}
@ -1972,31 +1981,64 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
u64 bytenr , u64 num_bytes ,
u64 parent , u64 root_objectid ,
u64 owner , u64 offset , int refs_to_add ,
int no_quota ,
struct btrfs_delayed_extent_op * extent_op )
{
struct btrfs_fs_info * fs_info = root - > fs_info ;
struct btrfs_path * path ;
struct extent_buffer * leaf ;
struct btrfs_extent_item * item ;
struct btrfs_key key ;
u64 refs ;
int ret ;
enum btrfs_qgroup_operation_type type = BTRFS_QGROUP_OPER_ADD_EXCL ;
path = btrfs_alloc_path ( ) ;
if ( ! path )
return - ENOMEM ;
if ( ! is_fstree ( root_objectid ) | | ! root - > fs_info - > quota_enabled )
no_quota = 1 ;
path - > reada = 1 ;
path - > leave_spinning = 1 ;
/* this will setup the path even if it fails to insert the back ref */
ret = insert_inline_extent_backref ( trans , root - > fs_info - > extent_root ,
path , bytenr , num_bytes , parent ,
ret = insert_inline_extent_backref ( trans , fs_info - > extent_root , path ,
bytenr , num_bytes , parent ,
root_objectid , owner , offset ,
refs_to_add , extent_op ) ;
if ( ret ! = - EAGAIN )
if ( ( ret < 0 & & ret ! = - EAGAIN ) | | ( ! ret & & no_quota ) )
goto out ;
/*
* Ok we were able to insert an inline extent and it appears to be a new
* reference , deal with the qgroup accounting .
*/
if ( ! ret & & ! no_quota ) {
ASSERT ( root - > fs_info - > quota_enabled ) ;
leaf = path - > nodes [ 0 ] ;
btrfs_item_key_to_cpu ( leaf , & key , path - > slots [ 0 ] ) ;
item = btrfs_item_ptr ( leaf , path - > slots [ 0 ] ,
struct btrfs_extent_item ) ;
if ( btrfs_extent_refs ( leaf , item ) > ( u64 ) refs_to_add )
type = BTRFS_QGROUP_OPER_ADD_SHARED ;
btrfs_release_path ( path ) ;
ret = btrfs_qgroup_record_ref ( trans , fs_info , root_objectid ,
bytenr , num_bytes , type , 0 ) ;
goto out ;
}
/*
* Ok we had - EAGAIN which means we didn ' t have space to insert and
* inline extent ref , so just update the reference count and add a
* normal backref .
*/
leaf = path - > nodes [ 0 ] ;
btrfs_item_key_to_cpu ( leaf , & key , path - > slots [ 0 ] ) ;
item = btrfs_item_ptr ( leaf , path - > slots [ 0 ] , struct btrfs_extent_item ) ;
refs = btrfs_extent_refs ( leaf , item ) ;
if ( refs )
type = BTRFS_QGROUP_OPER_ADD_SHARED ;
btrfs_set_extent_refs ( leaf , item , refs + refs_to_add ) ;
if ( extent_op )
__run_delayed_extent_op ( extent_op , leaf , item ) ;
@ -2004,9 +2046,15 @@ static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty ( leaf ) ;
btrfs_release_path ( path ) ;
if ( ! no_quota ) {
ret = btrfs_qgroup_record_ref ( trans , fs_info , root_objectid ,
bytenr , num_bytes , type , 0 ) ;
if ( ret )
goto out ;
}
path - > reada = 1 ;
path - > leave_spinning = 1 ;
/* now insert the actual backref */
ret = insert_extent_backref ( trans , root - > fs_info - > extent_root ,
path , bytenr , parent , root_objectid ,
@ -2040,8 +2088,7 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
if ( node - > type = = BTRFS_SHARED_DATA_REF_KEY )
parent = ref - > parent ;
else
ref_root = ref - > root ;
ref_root = ref - > root ;
if ( node - > action = = BTRFS_ADD_DELAYED_REF & & insert_reserved ) {
if ( extent_op )
@ -2055,13 +2102,13 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
node - > num_bytes , parent ,
ref_root , ref - > objectid ,
ref - > offset , node - > ref_mod ,
extent_op ) ;
node - > no_quota , extent_op ) ;
} else if ( node - > action = = BTRFS_DROP_DELAYED_REF ) {
ret = __btrfs_free_extent ( trans , root , node - > bytenr ,
node - > num_bytes , parent ,
ref_root , ref - > objectid ,
ref - > offset , node - > ref_mod ,
extent_op ) ;
extent_op , node - > no_quota ) ;
} else {
BUG ( ) ;
}
@ -2198,8 +2245,7 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
if ( node - > type = = BTRFS_SHARED_BLOCK_REF_KEY )
parent = ref - > parent ;
else
ref_root = ref - > root ;
ref_root = ref - > root ;
ins . objectid = node - > bytenr ;
if ( skinny_metadata ) {
@ -2217,15 +2263,18 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
parent , ref_root ,
extent_op - > flags_to_set ,
& extent_op - > key ,
ref - > level , & ins ) ;
ref - > level , & ins ,
node - > no_quota ) ;
} else if ( node - > action = = BTRFS_ADD_DELAYED_REF ) {
ret = __btrfs_inc_extent_ref ( trans , root , node - > bytenr ,
node - > num_bytes , parent , ref_root ,
ref - > level , 0 , 1 , extent_op ) ;
ref - > level , 0 , 1 , node - > no_quota ,
extent_op ) ;
} else if ( node - > action = = BTRFS_DROP_DELAYED_REF ) {
ret = __btrfs_free_extent ( trans , root , node - > bytenr ,
node - > num_bytes , parent , ref_root ,
ref - > level , 0 , 1 , extent_op ) ;
ref - > level , 0 , 1 , extent_op ,
node - > no_quota ) ;
} else {
BUG ( ) ;
}
@ -2573,42 +2622,6 @@ static u64 find_middle(struct rb_root *root)
}
# endif
int btrfs_delayed_refs_qgroup_accounting ( struct btrfs_trans_handle * trans ,
struct btrfs_fs_info * fs_info )
{
struct qgroup_update * qgroup_update ;
int ret = 0 ;
if ( list_empty ( & trans - > qgroup_ref_list ) ! =
! trans - > delayed_ref_elem . seq ) {
/* list without seq or seq without list */
btrfs_err ( fs_info ,
" qgroup accounting update error, list is%s empty, seq is %#x.%x " ,
list_empty ( & trans - > qgroup_ref_list ) ? " " : " not " ,
( u32 ) ( trans - > delayed_ref_elem . seq > > 32 ) ,
( u32 ) trans - > delayed_ref_elem . seq ) ;
BUG ( ) ;
}
if ( ! trans - > delayed_ref_elem . seq )
return 0 ;
while ( ! list_empty ( & trans - > qgroup_ref_list ) ) {
qgroup_update = list_first_entry ( & trans - > qgroup_ref_list ,
struct qgroup_update , list ) ;
list_del ( & qgroup_update - > list ) ;
if ( ! ret )
ret = btrfs_qgroup_account_ref (
trans , fs_info , qgroup_update - > node ,
qgroup_update - > extent_op ) ;
kfree ( qgroup_update ) ;
}
btrfs_put_tree_mod_seq ( fs_info , & trans - > delayed_ref_elem ) ;
return ret ;
}
static inline u64 heads_to_leaves ( struct btrfs_root * root , u64 heads )
{
u64 num_bytes ;
@ -2697,8 +2710,6 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
if ( root = = root - > fs_info - > extent_root )
root = root - > fs_info - > tree_root ;
btrfs_delayed_refs_qgroup_accounting ( trans , root - > fs_info ) ;
delayed_refs = & trans - > transaction - > delayed_refs ;
if ( count = = 0 ) {
count = atomic_read ( & delayed_refs - > num_entries ) * 2 ;
@ -2757,6 +2768,9 @@ again:
goto again ;
}
out :
ret = btrfs_delayed_qgroup_accounting ( trans , root - > fs_info ) ;
if ( ret )
return ret ;
assert_qgroups_uptodate ( trans ) ;
return 0 ;
}
@ -2963,7 +2977,7 @@ out:
static int __btrfs_mod_ref ( struct btrfs_trans_handle * trans ,
struct btrfs_root * root ,
struct extent_buffer * buf ,
int full_backref , int inc , int for_cow )
int full_backref , int inc , int no_quota )
{
u64 bytenr ;
u64 num_bytes ;
@ -3013,7 +3027,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
key . offset - = btrfs_file_extent_offset ( buf , fi ) ;
ret = process_func ( trans , root , bytenr , num_bytes ,
parent , ref_root , key . objectid ,
key . offset , for_cow ) ;
key . offset , no_quota ) ;
if ( ret )
goto fail ;
} else {
@ -3021,7 +3035,7 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
num_bytes = btrfs_level_size ( root , level - 1 ) ;
ret = process_func ( trans , root , bytenr , num_bytes ,
parent , ref_root , level - 1 , 0 ,
for_cow ) ;
no_quota ) ;
if ( ret )
goto fail ;
}
@ -3032,15 +3046,15 @@ fail:
}
int btrfs_inc_ref ( struct btrfs_trans_handle * trans , struct btrfs_root * root ,
struct extent_buffer * buf , int full_backref , int for_cow )
struct extent_buffer * buf , int full_backref , int no_quota )
{
return __btrfs_mod_ref ( trans , root , buf , full_backref , 1 , for_cow ) ;
return __btrfs_mod_ref ( trans , root , buf , full_backref , 1 , no_quota ) ;
}
int btrfs_dec_ref ( struct btrfs_trans_handle * trans , struct btrfs_root * root ,
struct extent_buffer * buf , int full_backref , int for_cow )
struct extent_buffer * buf , int full_backref , int no_quota )
{
return __btrfs_mod_ref ( trans , root , buf , full_backref , 0 , for_cow ) ;
return __btrfs_mod_ref ( trans , root , buf , full_backref , 0 , no_quota ) ;
}
static int write_one_cache_group ( struct btrfs_trans_handle * trans ,
@ -5723,7 +5737,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
u64 bytenr , u64 num_bytes , u64 parent ,
u64 root_objectid , u64 owner_objectid ,
u64 owner_offset , int refs_to_drop ,
struct btrfs_delayed_extent_op * extent_op )
struct btrfs_delayed_extent_op * extent_op ,
int no_quota )
{
struct btrfs_key key ;
struct btrfs_path * path ;
@ -5739,9 +5754,14 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
int num_to_del = 1 ;
u32 item_size ;
u64 refs ;
int last_ref = 0 ;
enum btrfs_qgroup_operation_type type = BTRFS_QGROUP_OPER_SUB_EXCL ;
bool skinny_metadata = btrfs_fs_incompat ( root - > fs_info ,
SKINNY_METADATA ) ;
if ( ! info - > quota_enabled | | ! is_fstree ( root_objectid ) )
no_quota = 1 ;
path = btrfs_alloc_path ( ) ;
if ( ! path )
return - ENOMEM ;
@ -5789,7 +5809,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
BUG_ON ( iref ) ;
ret = remove_extent_backref ( trans , extent_root , path ,
NULL , refs_to_drop ,
is_data ) ;
is_data , & last_ref ) ;
if ( ret ) {
btrfs_abort_transaction ( trans , extent_root , ret ) ;
goto out ;
@ -5916,6 +5936,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
refs - = refs_to_drop ;
if ( refs > 0 ) {
type = BTRFS_QGROUP_OPER_SUB_SHARED ;
if ( extent_op )
__run_delayed_extent_op ( extent_op , leaf , ei ) ;
/*
@ -5931,7 +5952,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
if ( found_extent ) {
ret = remove_extent_backref ( trans , extent_root , path ,
iref , refs_to_drop ,
is_data ) ;
is_data , & last_ref ) ;
if ( ret ) {
btrfs_abort_transaction ( trans , extent_root , ret ) ;
goto out ;
@ -5952,6 +5973,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
}
}
last_ref = 1 ;
ret = btrfs_del_items ( trans , extent_root , path , path - > slots [ 0 ] ,
num_to_del ) ;
if ( ret ) {
@ -5974,6 +5996,20 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
goto out ;
}
}
btrfs_release_path ( path ) ;
/* Deal with the quota accounting */
if ( ! ret & & last_ref & & ! no_quota ) {
int mod_seq = 0 ;
if ( owner_objectid > = BTRFS_FIRST_FREE_OBJECTID & &
type = = BTRFS_QGROUP_OPER_SUB_SHARED )
mod_seq = 1 ;
ret = btrfs_qgroup_record_ref ( trans , info , root_objectid ,
bytenr , num_bytes , type ,
mod_seq ) ;
}
out :
btrfs_free_path ( path ) ;
return ret ;
@ -6110,7 +6146,7 @@ out:
/* Can return -ENOMEM */
int btrfs_free_extent ( struct btrfs_trans_handle * trans , struct btrfs_root * root ,
u64 bytenr , u64 num_bytes , u64 parent , u64 root_objectid ,
u64 owner , u64 offset , int for_cow )
u64 owner , u64 offset , int no_quota )
{
int ret ;
struct btrfs_fs_info * fs_info = root - > fs_info ;
@ -6130,13 +6166,13 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
ret = btrfs_add_delayed_tree_ref ( fs_info , trans , bytenr ,
num_bytes ,
parent , root_objectid , ( int ) owner ,
BTRFS_DROP_DELAYED_REF , NULL , for_cow ) ;
BTRFS_DROP_DELAYED_REF , NULL , no_quota ) ;
} else {
ret = btrfs_add_delayed_data_ref ( fs_info , trans , bytenr ,
num_bytes ,
parent , root_objectid , owner ,
offset , BTRFS_DROP_DELAYED_REF ,
NULL , for_cow ) ;
NULL , no_quota ) ;
}
return ret ;
}
@ -6842,6 +6878,13 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty ( path - > nodes [ 0 ] ) ;
btrfs_free_path ( path ) ;
/* Always set parent to 0 here since its exclusive anyway. */
ret = btrfs_qgroup_record_ref ( trans , fs_info , root_objectid ,
ins - > objectid , ins - > offset ,
BTRFS_QGROUP_OPER_ADD_EXCL , 0 ) ;
if ( ret )
return ret ;
ret = update_block_group ( root , ins - > objectid , ins - > offset , 1 ) ;
if ( ret ) { /* -ENOENT, logic error */
btrfs_err ( fs_info , " update block group failed for %llu %llu " ,
@ -6856,7 +6899,8 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_root * root ,
u64 parent , u64 root_objectid ,
u64 flags , struct btrfs_disk_key * key ,
int level , struct btrfs_key * ins )
int level , struct btrfs_key * ins ,
int no_quota )
{
int ret ;
struct btrfs_fs_info * fs_info = root - > fs_info ;
@ -6866,6 +6910,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
struct btrfs_path * path ;
struct extent_buffer * leaf ;
u32 size = sizeof ( * extent_item ) + sizeof ( * iref ) ;
u64 num_bytes = ins - > offset ;
bool skinny_metadata = btrfs_fs_incompat ( root - > fs_info ,
SKINNY_METADATA ) ;
@ -6899,6 +6944,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
if ( skinny_metadata ) {
iref = ( struct btrfs_extent_inline_ref * ) ( extent_item + 1 ) ;
num_bytes = root - > leafsize ;
} else {
block_info = ( struct btrfs_tree_block_info * ) ( extent_item + 1 ) ;
btrfs_set_tree_block_key ( leaf , block_info , key ) ;
@ -6920,6 +6966,14 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
btrfs_mark_buffer_dirty ( leaf ) ;
btrfs_free_path ( path ) ;
if ( ! no_quota ) {
ret = btrfs_qgroup_record_ref ( trans , fs_info , root_objectid ,
ins - > objectid , num_bytes ,
BTRFS_QGROUP_OPER_ADD_EXCL , 0 ) ;
if ( ret )
return ret ;
}
ret = update_block_group ( root , ins - > objectid , root - > leafsize , 1 ) ;
if ( ret ) { /* -ENOENT, logic error */
btrfs_err ( fs_info , " update block group failed for %llu %llu " ,