2022-01-04 22:32:09 -05:00
// SPDX-License-Identifier: GPL-2.0
# include "bcachefs.h"
# include "buckets_waiting_for_journal.h"
# include <linux/hash.h>
# include <linux/random.h>
static inline struct bucket_hashed *
bucket_hash ( struct buckets_waiting_for_journal_table * t ,
unsigned hash_seed_idx , u64 dev_bucket )
{
return t - > d + hash_64 ( dev_bucket ^ t - > hash_seeds [ hash_seed_idx ] , t - > bits ) ;
}
static void bucket_table_init ( struct buckets_waiting_for_journal_table * t , size_t bits )
{
unsigned i ;
t - > bits = bits ;
for ( i = 0 ; i < ARRAY_SIZE ( t - > hash_seeds ) ; i + + )
get_random_bytes ( & t - > hash_seeds [ i ] , sizeof ( t - > hash_seeds [ i ] ) ) ;
memset ( t - > d , 0 , sizeof ( t - > d [ 0 ] ) < < t - > bits ) ;
}
bool bch2_bucket_needs_journal_commit ( struct buckets_waiting_for_journal * b ,
u64 flushed_seq ,
unsigned dev , u64 bucket )
{
struct buckets_waiting_for_journal_table * t ;
u64 dev_bucket = ( u64 ) dev < < 56 | bucket ;
bool ret = false ;
unsigned i ;
mutex_lock ( & b - > lock ) ;
t = b - > t ;
for ( i = 0 ; i < ARRAY_SIZE ( t - > hash_seeds ) ; i + + ) {
struct bucket_hashed * h = bucket_hash ( t , i , dev_bucket ) ;
if ( h - > dev_bucket = = dev_bucket ) {
ret = h - > journal_seq > flushed_seq ;
break ;
}
}
mutex_unlock ( & b - > lock ) ;
return ret ;
}
static bool bucket_table_insert ( struct buckets_waiting_for_journal_table * t ,
struct bucket_hashed * new ,
u64 flushed_seq )
{
struct bucket_hashed * last_evicted = NULL ;
unsigned tries , i ;
for ( tries = 0 ; tries < 10 ; tries + + ) {
struct bucket_hashed * old , * victim = NULL ;
for ( i = 0 ; i < ARRAY_SIZE ( t - > hash_seeds ) ; i + + ) {
old = bucket_hash ( t , i , new - > dev_bucket ) ;
if ( old - > dev_bucket = = new - > dev_bucket | |
old - > journal_seq < = flushed_seq ) {
* old = * new ;
return true ;
}
if ( last_evicted ! = old )
victim = old ;
}
/* hashed to same slot 3 times: */
if ( ! victim )
break ;
/* Failed to find an empty slot: */
swap ( * new , * victim ) ;
last_evicted = victim ;
}
return false ;
}
int bch2_set_bucket_needs_journal_commit ( struct buckets_waiting_for_journal * b ,
u64 flushed_seq ,
unsigned dev , u64 bucket ,
u64 journal_seq )
{
struct buckets_waiting_for_journal_table * t , * n ;
struct bucket_hashed tmp , new = {
. dev_bucket = ( u64 ) dev < < 56 | bucket ,
. journal_seq = journal_seq ,
} ;
size_t i , size , new_bits , nr_elements = 1 , nr_rehashes = 0 ;
int ret = 0 ;
mutex_lock ( & b - > lock ) ;
if ( likely ( bucket_table_insert ( b - > t , & new , flushed_seq ) ) )
goto out ;
t = b - > t ;
size = 1UL < < t - > bits ;
for ( i = 0 ; i < size ; i + + )
nr_elements + = t - > d [ i ] . journal_seq > flushed_seq ;
new_bits = t - > bits + ( nr_elements * 3 > size ) ;
n = kvmalloc ( sizeof ( * n ) + ( sizeof ( n - > d [ 0 ] ) < < new_bits ) , GFP_KERNEL ) ;
if ( ! n ) {
2023-03-14 15:35:57 -04:00
ret = - BCH_ERR_ENOMEM_buckets_waiting_for_journal_set ;
2022-01-04 22:32:09 -05:00
goto out ;
}
retry_rehash :
nr_rehashes + + ;
bucket_table_init ( n , new_bits ) ;
tmp = new ;
BUG_ON ( ! bucket_table_insert ( n , & tmp , flushed_seq ) ) ;
for ( i = 0 ; i < 1UL < < t - > bits ; i + + ) {
if ( t - > d [ i ] . journal_seq < = flushed_seq )
continue ;
tmp = t - > d [ i ] ;
if ( ! bucket_table_insert ( n , & tmp , flushed_seq ) )
goto retry_rehash ;
}
b - > t = n ;
kvfree ( t ) ;
bcachefs: Fix -Wformat in bch2_set_bucket_needs_journal_commit()
When building bcachefs for 32-bit ARM, there is a compiler warning in
bch2_set_bucket_needs_journal_commit() due to a debug print using the
wrong specifier:
fs/bcachefs/buckets_waiting_for_journal.c:137:30: error: format specifies type 'size_t' (aka 'unsigned int') but the argument has type 'unsigned long' [-Werror,-Wformat]
136 | pr_debug("took %zu rehashes, table at %zu/%zu elements",
| ~~~
| %lu
137 | nr_rehashes, nr_elements, 1UL << b->t->bits);
| ^~~~~~~~~~~~~~~~~
include/linux/printk.h:579:26: note: expanded from macro 'pr_debug'
579 | dynamic_pr_debug(fmt, ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dynamic_debug.h:270:22: note: expanded from macro 'dynamic_pr_debug'
270 | pr_fmt(fmt), ##__VA_ARGS__)
| ~~~ ^~~~~~~~~~~
include/linux/dynamic_debug.h:250:59: note: expanded from macro '_dynamic_func_call'
250 | _dynamic_func_call_cls(_DPRINTK_CLASS_DFLT, fmt, func, ##__VA_ARGS__)
| ^~~~~~~~~~~
include/linux/dynamic_debug.h:248:65: note: expanded from macro '_dynamic_func_call_cls'
248 | __dynamic_func_call_cls(__UNIQUE_ID(ddebug), cls, fmt, func, ##__VA_ARGS__)
| ^~~~~~~~~~~
include/linux/dynamic_debug.h:224:15: note: expanded from macro '__dynamic_func_call_cls'
224 | func(&id, ##__VA_ARGS__); \
| ^~~~~~~~~~~
1 error generated.
On 64-bit architectures, size_t is 'unsigned long', so there is no
warning when using %zu but on 32-bit architectures, size_t is
'unsigned int'. Use the correct specifier to resolve the warning.
Fixes: 7a82e75ddaef ("bcachefs: New data structure for buckets waiting on journal commit")
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2023-09-12 12:15:38 -07:00
pr_debug ( " took %zu rehashes, table at %zu/%lu elements " ,
2022-01-04 22:32:09 -05:00
nr_rehashes , nr_elements , 1UL < < b - > t - > bits ) ;
out :
mutex_unlock ( & b - > lock ) ;
return ret ;
}
void bch2_fs_buckets_waiting_for_journal_exit ( struct bch_fs * c )
{
struct buckets_waiting_for_journal * b = & c - > buckets_waiting_for_journal ;
kvfree ( b - > t ) ;
}
# define INITIAL_TABLE_BITS 3
int bch2_fs_buckets_waiting_for_journal_init ( struct bch_fs * c )
{
struct buckets_waiting_for_journal * b = & c - > buckets_waiting_for_journal ;
mutex_init ( & b - > lock ) ;
b - > t = kvmalloc ( sizeof ( * b - > t ) +
( sizeof ( b - > t - > d [ 0 ] ) < < INITIAL_TABLE_BITS ) , GFP_KERNEL ) ;
if ( ! b - > t )
2023-03-14 15:35:57 -04:00
return - BCH_ERR_ENOMEM_buckets_waiting_for_journal_init ;
2022-01-04 22:32:09 -05:00
bucket_table_init ( b - > t , INITIAL_TABLE_BITS ) ;
return 0 ;
}