2017-03-17 09:18:50 +03:00
/* SPDX-License-Identifier: GPL-2.0 */
# ifndef _BCACHEFS_BTREE_ITER_H
# define _BCACHEFS_BTREE_ITER_H
2019-01-14 00:02:22 +03:00
# include "bset.h"
2017-03-17 09:18:50 +03:00
# include "btree_types.h"
static inline void btree_iter_set_dirty ( struct btree_iter * iter ,
enum btree_iter_uptodate u )
{
iter - > uptodate = max_t ( unsigned , iter - > uptodate , u ) ;
}
static inline struct btree * btree_iter_node ( struct btree_iter * iter ,
unsigned level )
{
return level < BTREE_MAX_DEPTH ? iter - > l [ level ] . b : NULL ;
}
static inline struct btree * btree_node_parent ( struct btree_iter * iter ,
struct btree * b )
{
return btree_iter_node ( iter , b - > level + 1 ) ;
}
2019-03-28 05:03:30 +03:00
static inline bool btree_trans_has_multiple_iters ( const struct btree_trans * trans )
{
return hweight64 ( trans - > iters_linked ) > 1 ;
}
static inline int btree_iter_err ( const struct btree_iter * iter )
{
return iter - > flags & BTREE_ITER_ERROR ? - EIO : 0 ;
}
/* Iterate over iters within a transaction: */
static inline struct btree_iter *
__trans_next_iter ( struct btree_trans * trans , struct btree_iter * iter )
{
unsigned idx ;
/* XXX expensive pointer subtraction: */
for ( idx = iter - trans - > iters ;
idx < trans - > nr_iters ;
idx + + )
if ( trans - > iters_linked & ( 1ULL < < idx ) )
return & trans - > iters [ idx ] ;
return NULL ;
}
# define trans_for_each_iter(_trans, _iter) \
for ( _iter = ( _trans ) - > iters ; \
( _iter = __trans_next_iter ( ( _trans ) , _iter ) ) ; \
_iter + + )
2017-03-17 09:18:50 +03:00
static inline bool __iter_has_node ( const struct btree_iter * iter ,
const struct btree * b )
{
/*
* We don ' t compare the low bits of the lock sequence numbers because
* @ iter might have taken a write lock on @ b , and we don ' t want to skip
* the linked iterator if the sequence numbers were equal before taking
* that write lock . The lock sequence number is incremented by taking
* and releasing write locks and is even when unlocked :
*/
return iter - > l [ b - > level ] . b = = b & &
2018-08-05 21:41:29 +03:00
iter - > l [ b - > level ] . lock_seq > > 1 = = b - > lock . state . seq > > 1 ;
2017-03-17 09:18:50 +03:00
}
static inline struct btree_iter *
2019-03-28 05:03:30 +03:00
__trans_next_iter_with_node ( struct btree_trans * trans , struct btree * b ,
struct btree_iter * iter )
2017-03-17 09:18:50 +03:00
{
2019-03-28 05:03:30 +03:00
unsigned idx ;
2017-03-17 09:18:50 +03:00
2019-03-28 05:03:30 +03:00
/* XXX expensive pointer subtraction: */
for ( idx = iter - trans - > iters ;
idx < trans - > nr_iters ;
idx + + ) {
if ( ! ( trans - > iters_linked & ( 1ULL < < idx ) ) )
continue ;
2017-03-17 09:18:50 +03:00
2019-03-28 05:03:30 +03:00
iter = & trans - > iters [ idx ] ;
if ( __iter_has_node ( iter , b ) )
return iter ;
}
return NULL ;
2017-03-17 09:18:50 +03:00
}
2019-03-28 05:03:30 +03:00
# define trans_for_each_iter_with_node(_trans, _b, _iter) \
for ( _iter = ( _trans ) - > iters ; \
( _iter = __trans_next_iter_with_node ( ( _trans ) , ( _b ) , _iter ) ) ; \
_iter + + )
2017-03-17 09:18:50 +03:00
# ifdef CONFIG_BCACHEFS_DEBUG
void bch2_btree_iter_verify ( struct btree_iter * , struct btree * ) ;
2019-03-28 05:03:30 +03:00
void bch2_btree_trans_verify_locks ( struct btree_trans * ) ;
2017-03-17 09:18:50 +03:00
# else
static inline void bch2_btree_iter_verify ( struct btree_iter * iter ,
struct btree * b ) { }
2019-03-28 05:03:30 +03:00
static inline void bch2_btree_trans_verify_locks ( struct btree_trans * iter ) { }
2017-03-17 09:18:50 +03:00
# endif
void bch2_btree_node_iter_fix ( struct btree_iter * , struct btree * ,
2018-08-12 02:12:05 +03:00
struct btree_node_iter * , struct bkey_packed * ,
unsigned , unsigned ) ;
2017-03-17 09:18:50 +03:00
int bch2_btree_iter_unlock ( struct btree_iter * ) ;
2019-03-28 05:03:30 +03:00
bool bch2_btree_trans_relock ( struct btree_trans * ) ;
void bch2_btree_trans_unlock ( struct btree_trans * ) ;
2017-03-17 09:18:50 +03:00
bool __bch2_btree_iter_upgrade ( struct btree_iter * , unsigned ) ;
bool __bch2_btree_iter_upgrade_nounlock ( struct btree_iter * , unsigned ) ;
static inline bool bch2_btree_iter_upgrade ( struct btree_iter * iter ,
unsigned new_locks_want ,
bool may_drop_locks )
{
new_locks_want = min ( new_locks_want , BTREE_MAX_DEPTH ) ;
return iter - > locks_want < new_locks_want
? ( may_drop_locks
? __bch2_btree_iter_upgrade ( iter , new_locks_want )
: __bch2_btree_iter_upgrade_nounlock ( iter , new_locks_want ) )
: iter - > uptodate < = BTREE_ITER_NEED_PEEK ;
}
void __bch2_btree_iter_downgrade ( struct btree_iter * , unsigned ) ;
static inline void bch2_btree_iter_downgrade ( struct btree_iter * iter )
{
if ( iter - > locks_want > ( iter - > flags & BTREE_ITER_INTENT ) ? 1 : 0 )
__bch2_btree_iter_downgrade ( iter , 0 ) ;
}
void bch2_btree_iter_node_replace ( struct btree_iter * , struct btree * ) ;
void bch2_btree_iter_node_drop ( struct btree_iter * , struct btree * ) ;
void bch2_btree_iter_reinit_node ( struct btree_iter * , struct btree * ) ;
int __must_check bch2_btree_iter_traverse ( struct btree_iter * ) ;
struct btree * bch2_btree_iter_peek_node ( struct btree_iter * ) ;
struct btree * bch2_btree_iter_next_node ( struct btree_iter * , unsigned ) ;
struct bkey_s_c bch2_btree_iter_peek ( struct btree_iter * ) ;
struct bkey_s_c bch2_btree_iter_next ( struct btree_iter * ) ;
struct bkey_s_c bch2_btree_iter_prev ( struct btree_iter * ) ;
struct bkey_s_c bch2_btree_iter_peek_slot ( struct btree_iter * ) ;
struct bkey_s_c bch2_btree_iter_next_slot ( struct btree_iter * ) ;
void bch2_btree_iter_set_pos_same_leaf ( struct btree_iter * , struct bpos ) ;
void bch2_btree_iter_set_pos ( struct btree_iter * , struct bpos ) ;
static inline struct bpos btree_type_successor ( enum btree_id id ,
struct bpos pos )
{
if ( id = = BTREE_ID_INODES ) {
pos . inode + + ;
pos . offset = 0 ;
} else if ( id ! = BTREE_ID_EXTENTS ) {
pos = bkey_successor ( pos ) ;
}
return pos ;
}
static inline struct bpos btree_type_predecessor ( enum btree_id id ,
struct bpos pos )
{
if ( id = = BTREE_ID_INODES ) {
- - pos . inode ;
pos . offset = 0 ;
} else /* if (id != BTREE_ID_EXTENTS) */ {
pos = bkey_predecessor ( pos ) ;
}
return pos ;
}
static inline int __btree_iter_cmp ( enum btree_id id ,
struct bpos pos ,
const struct btree_iter * r )
{
if ( id ! = r - > btree_id )
return id < r - > btree_id ? - 1 : 1 ;
return bkey_cmp ( pos , r - > pos ) ;
}
static inline int btree_iter_cmp ( const struct btree_iter * l ,
const struct btree_iter * r )
{
return __btree_iter_cmp ( l - > btree_id , l - > pos , r ) ;
}
2019-03-26 00:06:42 +03:00
int bch2_trans_unlock ( struct btree_trans * ) ;
2017-03-17 09:18:50 +03:00
/*
* Unlocks before scheduling
* Note : does not revalidate iterator
*/
2019-03-26 00:06:42 +03:00
static inline void bch2_trans_cond_resched ( struct btree_trans * trans )
2017-03-17 09:18:50 +03:00
{
if ( need_resched ( ) ) {
2019-03-26 00:06:42 +03:00
bch2_trans_unlock ( trans ) ;
2017-03-17 09:18:50 +03:00
schedule ( ) ;
} else if ( race_fault ( ) ) {
2019-03-26 00:06:42 +03:00
bch2_trans_unlock ( trans ) ;
2017-03-17 09:18:50 +03:00
}
}
2019-03-25 22:10:15 +03:00
# define __for_each_btree_node(_trans, _iter, _btree_id, _start, \
2017-03-17 09:18:50 +03:00
_locks_want , _depth , _flags , _b ) \
2019-03-25 22:10:15 +03:00
for ( iter = bch2_trans_get_node_iter ( ( _trans ) , ( _btree_id ) , \
_start , _locks_want , _depth , _flags ) , \
2017-03-17 09:18:50 +03:00
_b = bch2_btree_iter_peek_node ( _iter ) ; \
( _b ) ; \
( _b ) = bch2_btree_iter_next_node ( _iter , _depth ) )
2019-03-25 22:10:15 +03:00
# define for_each_btree_node(_trans, _iter, _btree_id, _start, \
_flags , _b ) \
__for_each_btree_node ( _trans , _iter , _btree_id , _start , \
0 , 0 , _flags , _b )
2017-03-17 09:18:50 +03:00
static inline struct bkey_s_c __bch2_btree_iter_peek ( struct btree_iter * iter ,
unsigned flags )
{
return flags & BTREE_ITER_SLOTS
? bch2_btree_iter_peek_slot ( iter )
: bch2_btree_iter_peek ( iter ) ;
}
static inline struct bkey_s_c __bch2_btree_iter_next ( struct btree_iter * iter ,
unsigned flags )
{
2019-03-26 00:06:42 +03:00
bch2_trans_cond_resched ( iter - > trans ) ;
2017-03-17 09:18:50 +03:00
return flags & BTREE_ITER_SLOTS
? bch2_btree_iter_next_slot ( iter )
: bch2_btree_iter_next ( iter ) ;
}
2019-03-25 22:10:15 +03:00
# define for_each_btree_key(_trans, _iter, _btree_id, _start, _flags, _k)\
for ( iter = bch2_trans_get_iter ( ( _trans ) , ( _btree_id ) , \
( _start ) , ( _flags ) ) , \
2017-03-17 09:18:50 +03:00
( _k ) = __bch2_btree_iter_peek ( _iter , _flags ) ; \
! IS_ERR_OR_NULL ( ( _k ) . k ) ; \
( _k ) = __bch2_btree_iter_next ( _iter , _flags ) )
# define for_each_btree_key_continue(_iter, _flags, _k) \
for ( ( _k ) = __bch2_btree_iter_peek ( _iter , _flags ) ; \
! IS_ERR_OR_NULL ( ( _k ) . k ) ; \
( _k ) = __bch2_btree_iter_next ( _iter , _flags ) )
2019-03-28 05:03:30 +03:00
static inline int bkey_err ( struct bkey_s_c k )
2017-03-17 09:18:50 +03:00
{
return PTR_ERR_OR_ZERO ( k . k ) ;
}
/* new multiple iterator interface: */
2018-08-09 04:22:46 +03:00
void bch2_trans_preload_iters ( struct btree_trans * ) ;
2019-03-25 22:10:15 +03:00
int bch2_trans_iter_put ( struct btree_trans * , struct btree_iter * ) ;
int bch2_trans_iter_free ( struct btree_trans * , struct btree_iter * ) ;
int bch2_trans_iter_free_on_commit ( struct btree_trans * , struct btree_iter * ) ;
2019-03-25 22:34:48 +03:00
void bch2_trans_unlink_iters ( struct btree_trans * , u64 ) ;
2017-03-17 09:18:50 +03:00
struct btree_iter * __bch2_trans_get_iter ( struct btree_trans * , enum btree_id ,
struct bpos , unsigned , u64 ) ;
2019-03-26 05:43:26 +03:00
struct btree_iter * bch2_trans_copy_iter ( struct btree_trans * ,
struct btree_iter * ) ;
2017-03-17 09:18:50 +03:00
static __always_inline u64 __btree_iter_id ( void )
{
u64 ret = 0 ;
ret < < = 32 ;
ret | = _RET_IP_ & U32_MAX ;
ret < < = 32 ;
ret | = _THIS_IP_ & U32_MAX ;
return ret ;
}
static __always_inline struct btree_iter *
bch2_trans_get_iter ( struct btree_trans * trans , enum btree_id btree_id ,
struct bpos pos , unsigned flags )
{
return __bch2_trans_get_iter ( trans , btree_id , pos , flags ,
__btree_iter_id ( ) ) ;
}
2019-03-25 22:10:15 +03:00
struct btree_iter * bch2_trans_get_node_iter ( struct btree_trans * ,
enum btree_id , struct bpos ,
unsigned , unsigned , unsigned ) ;
2018-07-13 06:30:45 +03:00
void __bch2_trans_begin ( struct btree_trans * ) ;
2018-08-09 01:42:04 +03:00
static inline void bch2_trans_begin_updates ( struct btree_trans * trans )
{
trans - > nr_updates = 0 ;
}
2017-03-17 09:18:50 +03:00
void * bch2_trans_kmalloc ( struct btree_trans * , size_t ) ;
void bch2_trans_init ( struct btree_trans * , struct bch_fs * ) ;
int bch2_trans_exit ( struct btree_trans * ) ;
2018-07-13 06:30:45 +03:00
# ifdef TRACE_TRANSACTION_RESTARTS
# define bch2_trans_begin(_trans) \
do { \
if ( is_power_of_2 ( ( _trans ) - > nr_restarts ) & & \
( _trans ) - > nr_restarts > = 8 ) \
pr_info ( " nr restarts: %zu " , ( _trans ) - > nr_restarts ) ; \
\
( _trans ) - > nr_restarts + + ; \
__bch2_trans_begin ( _trans ) ; \
} while ( 0 )
# else
# define bch2_trans_begin(_trans) __bch2_trans_begin(_trans)
# endif
# ifdef TRACE_TRANSACTION_RESTARTS_ALL
# define trans_restart(...) pr_info("transaction restart" __VA_ARGS__)
# else
# define trans_restart(...) no_printk("transaction restart" __VA_ARGS__)
# endif
2017-03-17 09:18:50 +03:00
# endif /* _BCACHEFS_BTREE_ITER_H */