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 {
2013-09-11 06:02:45 +04:00
struct closure cl ;
2013-03-24 03:11:31 +04:00
struct keybuf_key * w ;
2013-09-11 06:02:45 +04:00
struct data_insert_op op ;
2013-03-24 03:11:31 +04:00
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 ;
2014-02-18 03:48:36 +04:00
for ( i = 0 ; i < KEY_PTRS ( k ) ; i + + )
if ( ptr_available ( c , k , i ) & &
GC_MOVE ( PTR_BUCKET ( c , k , i ) ) )
2013-03-24 03:11:31 +04:00
return true ;
return false ;
}
/* Moving GC - IO loop */
static void moving_io_destructor ( struct closure * cl )
{
2013-09-11 06:02:45 +04:00
struct moving_io * io = container_of ( cl , struct moving_io , cl ) ;
2013-03-24 03:11:31 +04:00
kfree ( io ) ;
}
static void write_moving_finish ( struct closure * cl )
{
2013-09-11 06:02:45 +04:00
struct moving_io * io = container_of ( cl , struct moving_io , cl ) ;
2013-03-24 03:11:31 +04:00
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-09-11 06:02:45 +04:00
if ( io - > op . replace_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-09-11 06:02:45 +04:00
bch_keybuf_del ( & io - > op . c - > moving_gc_keys , io - > w ) ;
2013-03-24 03:11:31 +04:00
2013-09-11 06:02:45 +04:00
up ( & io - > op . 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 )
{
2013-12-17 02:12:09 +04:00
struct bbio * b = container_of ( bio , struct bbio , bio ) ;
2013-03-24 03:11:31 +04:00
struct moving_io * io = container_of ( bio - > bi_private ,
2013-09-11 06:02:45 +04:00
struct moving_io , cl ) ;
2013-03-24 03:11:31 +04:00
if ( error )
2013-09-11 06:02:45 +04:00
io - > op . error = error ;
2013-12-17 02:12:09 +04:00
else if ( ! KEY_DIRTY ( & b - > key ) & &
ptr_stale ( io - > op . c , & b - > key , 0 ) ) {
io - > op . error = - EINTR ;
}
2013-03-24 03:11:31 +04:00
2013-09-11 06:02:45 +04:00
bch_bbio_endio ( io - > op . 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 ) ) ;
2013-10-12 02:44:27 +04:00
bio - > bi_iter . bi_size = KEY_SIZE ( & io - > w - > key ) < < 9 ;
2013-03-24 03:11:31 +04:00
bio - > bi_max_vecs = DIV_ROUND_UP ( KEY_SIZE ( & io - > w - > key ) ,
PAGE_SECTORS ) ;
2013-09-11 06:02:45 +04:00
bio - > bi_private = & io - > cl ;
2013-03-24 03:11:31 +04:00
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 )
{
2013-09-11 06:02:45 +04:00
struct moving_io * io = container_of ( cl , struct moving_io , cl ) ;
struct data_insert_op * op = & io - > op ;
2013-03-24 03:11:31 +04:00
2013-09-11 06:02:45 +04:00
if ( ! op - > error ) {
2013-03-24 03:11:31 +04:00
moving_init ( io ) ;
2013-10-12 02:44:27 +04:00
io - > bio . bio . bi_iter . bi_sector = KEY_START ( & io - > w - > key ) ;
2013-09-11 06:02:45 +04:00
op - > write_prio = 1 ;
op - > bio = & io - > bio . bio ;
2013-03-24 03:11:31 +04:00
2013-09-11 06:02:45 +04:00
op - > writeback = KEY_DIRTY ( & io - > w - > key ) ;
op - > csum = KEY_CSUM ( & io - > w - > key ) ;
2013-03-24 03:11:31 +04:00
2013-09-11 06:02:45 +04:00
bkey_copy ( & op - > replace_key , & io - > w - > key ) ;
op - > replace = true ;
2013-03-24 03:11:31 +04:00
2013-09-11 06:02:45 +04:00
closure_call ( & op - > cl , bch_data_insert , NULL , cl ) ;
2013-03-24 03:11:31 +04:00
}
2014-01-10 04:03:04 +04:00
continue_at ( cl , write_moving_finish , op - > wq ) ;
2013-03-24 03:11:31 +04:00
}
static void read_moving_submit ( struct closure * cl )
{
2013-09-11 06:02:45 +04:00
struct moving_io * io = container_of ( cl , struct moving_io , cl ) ;
2013-03-24 03:11:31 +04:00
struct bio * bio = & io - > bio . bio ;
2013-09-11 06:02:45 +04:00
bch_submit_bbio ( bio , io - > op . c , & io - > w - > key , 0 ) ;
2013-03-24 03:11:31 +04:00
2014-01-10 04:03:04 +04:00
continue_at ( cl , write_moving , io - > op . 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 ;
2013-12-17 02:12:09 +04:00
if ( ptr_stale ( c , & w - > key , 0 ) ) {
bch_keybuf_del ( & c - > moving_gc_keys , w ) ;
continue ;
}
2013-03-24 03:11:31 +04:00
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-09-11 06:02:45 +04:00
io - > op . inode = KEY_INODE ( & w - > key ) ;
io - > op . c = c ;
2014-01-10 04:03:04 +04:00
io - > op . wq = c - > moving_gc_wq ;
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 ) ;
2013-09-11 06:02:45 +04:00
closure_call ( & io - > 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 )
{
2013-11-01 06:25:18 +04:00
struct bucket * b ;
return ( b = heap_peek ( & ca - > heap ) ) ? GC_SECTORS_USED ( b ) : 0 ;
2013-03-25 22:46:44 +04:00
}
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 *
2013-12-17 13:29:34 +04:00
fifo_used ( & ca - > free [ RESERVE_MOVINGGC ] ) ;
2013-03-24 03:11:31 +04:00
ca - > heap . used = 0 ;
for_each_bucket ( b , ca ) {
2014-01-24 03:21:02 +04:00
if ( GC_MARK ( b ) = = GC_MARK_METADATA | |
! GC_SECTORS_USED ( b ) | |
GC_SECTORS_USED ( b ) = = ca - > sb . bucket_size | |
atomic_read ( & b - > pin ) )
2013-03-24 03:11:31 +04:00
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-11-08 05:53:19 +04:00
while ( heap_pop ( & ca - > heap , b , bucket_cmp ) )
SET_GC_MOVE ( b , 1 ) ;
2013-03-24 03:11:31 +04:00
}
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
}