2013-03-24 03:11:31 +04:00
/*
* Moving / copying garbage collector
*
* Copyright 2012 Google , Inc .
*/
# include "bcache.h"
# include "btree.h"
# include "debug.h"
# include "request.h"
2013-04-27 02:39:55 +04:00
# include <trace/events/bcache.h>
2013-03-24 03:11:31 +04:00
struct moving_io {
struct keybuf_key * w ;
struct search s ;
struct bbio bio ;
} ;
static bool moving_pred ( struct keybuf * buf , struct bkey * k )
{
struct cache_set * c = container_of ( buf , struct cache_set ,
moving_gc_keys ) ;
unsigned i ;
for ( i = 0 ; i < KEY_PTRS ( k ) ; i + + ) {
struct cache * ca = PTR_CACHE ( c , k , i ) ;
struct bucket * g = PTR_BUCKET ( c , k , i ) ;
if ( GC_SECTORS_USED ( g ) < ca - > gc_move_threshold )
return true ;
}
return false ;
}
/* Moving GC - IO loop */
static void moving_io_destructor ( struct closure * cl )
{
struct moving_io * io = container_of ( cl , struct moving_io , s . cl ) ;
kfree ( io ) ;
}
static void write_moving_finish ( struct closure * cl )
{
struct moving_io * io = container_of ( cl , struct moving_io , s . cl ) ;
struct bio * bio = & io - > bio . bio ;
2013-06-07 05:15:57 +04:00
struct bio_vec * bv ;
int i ;
2013-03-24 03:11:31 +04:00
2013-06-07 05:15:57 +04:00
bio_for_each_segment_all ( bv , bio , i )
2013-03-24 03:11:31 +04:00
__free_page ( bv - > bv_page ) ;
2013-07-25 05:06:22 +04:00
if ( io - > s . insert_collision )
2013-04-27 02:39:55 +04:00
trace_bcache_gc_copy_collision ( & io - > w - > key ) ;
2013-03-24 03:11:31 +04:00
2013-07-25 04:44:17 +04:00
bch_keybuf_del ( & io - > s . c - > moving_gc_keys , io - > w ) ;
2013-03-24 03:11:31 +04:00
2013-07-25 04:44:17 +04:00
up ( & io - > s . c - > moving_in_flight ) ;
2013-03-24 03:11:31 +04:00
closure_return_with_destructor ( cl , moving_io_destructor ) ;
}
static void read_moving_endio ( struct bio * bio , int error )
{
struct moving_io * io = container_of ( bio - > bi_private ,
struct moving_io , s . cl ) ;
if ( error )
io - > s . error = error ;
2013-07-25 04:44:17 +04:00
bch_bbio_endio ( io - > s . c , bio , error , " reading data to move " ) ;
2013-03-24 03:11:31 +04:00
}
static void moving_init ( struct moving_io * io )
{
struct bio * bio = & io - > bio . bio ;
bio_init ( bio ) ;
bio_get ( bio ) ;
bio_set_prio ( bio , IOPRIO_PRIO_VALUE ( IOPRIO_CLASS_IDLE , 0 ) ) ;
bio - > bi_size = KEY_SIZE ( & io - > w - > key ) < < 9 ;
bio - > bi_max_vecs = DIV_ROUND_UP ( KEY_SIZE ( & io - > w - > key ) ,
PAGE_SECTORS ) ;
bio - > bi_private = & io - > s . cl ;
bio - > bi_io_vec = bio - > bi_inline_vecs ;
2013-03-28 22:50:55 +04:00
bch_bio_map ( bio , NULL ) ;
2013-03-24 03:11:31 +04:00
}
static void write_moving ( struct closure * cl )
{
struct search * s = container_of ( cl , struct search , cl ) ;
struct moving_io * io = container_of ( s , struct moving_io , s ) ;
if ( ! s - > error ) {
moving_init ( io ) ;
io - > bio . bio . bi_sector = KEY_START ( & io - > w - > key ) ;
s - > op . lock = - 1 ;
2013-07-25 04:44:17 +04:00
s - > write_prio = 1 ;
s - > cache_bio = & io - > bio . bio ;
2013-03-24 03:11:31 +04:00
s - > writeback = KEY_DIRTY ( & io - > w - > key ) ;
2013-07-25 04:44:17 +04:00
s - > csum = KEY_CSUM ( & io - > w - > key ) ;
2013-03-24 03:11:31 +04:00
2013-09-11 05:52:54 +04:00
bkey_copy ( & s - > replace_key , & io - > w - > key ) ;
s - > replace = true ;
2013-03-24 03:11:31 +04:00
2013-07-25 05:04:18 +04:00
closure_init ( & s - > btree , cl ) ;
bch_data_insert ( & s - > btree ) ;
2013-03-24 03:11:31 +04:00
}
2013-10-25 04:19:26 +04:00
continue_at ( cl , write_moving_finish , system_wq ) ;
2013-03-24 03:11:31 +04:00
}
static void read_moving_submit ( struct closure * cl )
{
struct search * s = container_of ( cl , struct search , cl ) ;
struct moving_io * io = container_of ( s , struct moving_io , s ) ;
struct bio * bio = & io - > bio . bio ;
2013-07-25 04:44:17 +04:00
bch_submit_bbio ( bio , s - > c , & io - > w - > key , 0 ) ;
2013-03-24 03:11:31 +04:00
2013-10-25 04:19:26 +04:00
continue_at ( cl , write_moving , system_wq ) ;
2013-03-24 03:11:31 +04:00
}
2013-10-25 04:19:26 +04:00
static void read_moving ( struct cache_set * c )
2013-03-24 03:11:31 +04:00
{
struct keybuf_key * w ;
struct moving_io * io ;
struct bio * bio ;
2013-10-25 04:19:26 +04:00
struct closure cl ;
closure_init_stack ( & cl ) ;
2013-03-24 03:11:31 +04:00
/* XXX: if we error, background writeback could stall indefinitely */
while ( ! test_bit ( CACHE_SET_STOPPING , & c - > flags ) ) {
2013-06-05 17:24:39 +04:00
w = bch_keybuf_next_rescan ( c , & c - > moving_gc_keys ,
& MAX_KEY , moving_pred ) ;
2013-03-24 03:11:31 +04:00
if ( ! w )
break ;
io = kzalloc ( sizeof ( struct moving_io ) + sizeof ( struct bio_vec )
* DIV_ROUND_UP ( KEY_SIZE ( & w - > key ) , PAGE_SECTORS ) ,
GFP_KERNEL ) ;
if ( ! io )
goto err ;
w - > private = io ;
io - > w = w ;
2013-07-25 04:44:17 +04:00
io - > s . inode = KEY_INODE ( & w - > key ) ;
io - > s . c = c ;
2013-03-24 03:11:31 +04:00
moving_init ( io ) ;
bio = & io - > bio . bio ;
bio - > bi_rw = READ ;
bio - > bi_end_io = read_moving_endio ;
2013-06-07 05:15:57 +04:00
if ( bio_alloc_pages ( bio , GFP_KERNEL ) )
2013-03-24 03:11:31 +04:00
goto err ;
2013-04-27 02:39:55 +04:00
trace_bcache_gc_copy ( & w - > key ) ;
2013-03-24 03:11:31 +04:00
2013-10-25 04:19:26 +04:00
down ( & c - > moving_in_flight ) ;
closure_call ( & io - > s . cl , read_moving_submit , NULL , & cl ) ;
2013-03-24 03:11:31 +04:00
}
if ( 0 ) {
err : if ( ! IS_ERR_OR_NULL ( w - > private ) )
kfree ( w - > private ) ;
bch_keybuf_del ( & c - > moving_gc_keys , w ) ;
}
2013-10-25 04:19:26 +04:00
closure_sync ( & cl ) ;
2013-03-24 03:11:31 +04:00
}
2013-03-25 22:46:44 +04:00
static bool bucket_cmp ( struct bucket * l , struct bucket * r )
{
return GC_SECTORS_USED ( l ) < GC_SECTORS_USED ( r ) ;
}
static unsigned bucket_heap_top ( struct cache * ca )
{
return GC_SECTORS_USED ( heap_peek ( & ca - > heap ) ) ;
}
2013-10-25 04:19:26 +04:00
void bch_moving_gc ( struct cache_set * c )
2013-03-24 03:11:31 +04:00
{
struct cache * ca ;
struct bucket * b ;
unsigned i ;
if ( ! c - > copy_gc_enabled )
2013-10-25 04:19:26 +04:00
return ;
2013-03-24 03:11:31 +04:00
mutex_lock ( & c - > bucket_lock ) ;
for_each_cache ( ca , c , i ) {
unsigned sectors_to_move = 0 ;
unsigned reserve_sectors = ca - > sb . bucket_size *
min ( fifo_used ( & ca - > free ) , ca - > free . size / 2 ) ;
ca - > heap . used = 0 ;
for_each_bucket ( b , ca ) {
if ( ! GC_SECTORS_USED ( b ) )
continue ;
if ( ! heap_full ( & ca - > heap ) ) {
sectors_to_move + = GC_SECTORS_USED ( b ) ;
heap_add ( & ca - > heap , b , bucket_cmp ) ;
} else if ( bucket_cmp ( b , heap_peek ( & ca - > heap ) ) ) {
2013-03-25 22:46:44 +04:00
sectors_to_move - = bucket_heap_top ( ca ) ;
2013-03-24 03:11:31 +04:00
sectors_to_move + = GC_SECTORS_USED ( b ) ;
ca - > heap . data [ 0 ] = b ;
heap_sift ( & ca - > heap , 0 , bucket_cmp ) ;
}
}
while ( sectors_to_move > reserve_sectors ) {
heap_pop ( & ca - > heap , b , bucket_cmp ) ;
sectors_to_move - = GC_SECTORS_USED ( b ) ;
}
2013-03-25 22:46:44 +04:00
ca - > gc_move_threshold = bucket_heap_top ( ca ) ;
2013-03-24 03:11:31 +04:00
pr_debug ( " threshold %u " , ca - > gc_move_threshold ) ;
}
mutex_unlock ( & c - > bucket_lock ) ;
c - > moving_gc_keys . last_scanned = ZERO_KEY ;
2013-10-25 04:19:26 +04:00
read_moving ( c ) ;
2013-03-24 03:11:31 +04:00
}
void bch_moving_init_cache_set ( struct cache_set * c )
{
2013-06-05 17:24:39 +04:00
bch_keybuf_init ( & c - > moving_gc_keys ) ;
2013-10-25 04:19:26 +04:00
sema_init ( & c - > moving_in_flight , 64 ) ;
2013-03-24 03:11:31 +04:00
}