@ -457,6 +457,7 @@ static void blk_throtl_update_limit_valid(struct throtl_data *td)
td - > limit_valid [ LIMIT_LOW ] = low_valid ;
td - > limit_valid [ LIMIT_LOW ] = low_valid ;
}
}
static void throtl_upgrade_state ( struct throtl_data * td ) ;
static void throtl_pd_offline ( struct blkg_policy_data * pd )
static void throtl_pd_offline ( struct blkg_policy_data * pd )
{
{
struct throtl_grp * tg = pd_to_tg ( pd ) ;
struct throtl_grp * tg = pd_to_tg ( pd ) ;
@ -468,9 +469,8 @@ static void throtl_pd_offline(struct blkg_policy_data *pd)
blk_throtl_update_limit_valid ( tg - > td ) ;
blk_throtl_update_limit_valid ( tg - > td ) ;
if ( tg - > td - > limit_index = = LIMIT_LOW & &
if ( ! tg - > td - > limit_valid [ tg - > td - > limit_index ] )
! tg - > td - > limit_valid [ LIMIT_LOW ] )
throtl_upgrade_state ( tg - > td ) ;
tg - > td - > limit_index = LIMIT_MAX ;
}
}
static void throtl_pd_free ( struct blkg_policy_data * pd )
static void throtl_pd_free ( struct blkg_policy_data * pd )
@ -1081,6 +1081,8 @@ static int throtl_select_dispatch(struct throtl_service_queue *parent_sq)
return nr_disp ;
return nr_disp ;
}
}
static bool throtl_can_upgrade ( struct throtl_data * td ,
struct throtl_grp * this_tg ) ;
/**
/**
* throtl_pending_timer_fn - timer function for service_queue - > pending_timer
* throtl_pending_timer_fn - timer function for service_queue - > pending_timer
* @ arg : the throtl_service_queue being serviced
* @ arg : the throtl_service_queue being serviced
@ -1107,6 +1109,9 @@ static void throtl_pending_timer_fn(unsigned long arg)
int ret ;
int ret ;
spin_lock_irq ( q - > queue_lock ) ;
spin_lock_irq ( q - > queue_lock ) ;
if ( throtl_can_upgrade ( td , NULL ) )
throtl_upgrade_state ( td ) ;
again :
again :
parent_sq = sq - > parent_sq ;
parent_sq = sq - > parent_sq ;
dispatched = false ;
dispatched = false ;
@ -1522,6 +1527,87 @@ static struct blkcg_policy blkcg_policy_throtl = {
. pd_free_fn = throtl_pd_free ,
. pd_free_fn = throtl_pd_free ,
} ;
} ;
static bool throtl_tg_can_upgrade ( struct throtl_grp * tg )
{
struct throtl_service_queue * sq = & tg - > service_queue ;
bool read_limit , write_limit ;
/*
* if cgroup reaches low limit ( if low limit is 0 , the cgroup always
* reaches ) , it ' s ok to upgrade to next limit
*/
read_limit = tg - > bps [ READ ] [ LIMIT_LOW ] | | tg - > iops [ READ ] [ LIMIT_LOW ] ;
write_limit = tg - > bps [ WRITE ] [ LIMIT_LOW ] | | tg - > iops [ WRITE ] [ LIMIT_LOW ] ;
if ( ! read_limit & & ! write_limit )
return true ;
if ( read_limit & & sq - > nr_queued [ READ ] & &
( ! write_limit | | sq - > nr_queued [ WRITE ] ) )
return true ;
if ( write_limit & & sq - > nr_queued [ WRITE ] & &
( ! read_limit | | sq - > nr_queued [ READ ] ) )
return true ;
return false ;
}
static bool throtl_hierarchy_can_upgrade ( struct throtl_grp * tg )
{
while ( true ) {
if ( throtl_tg_can_upgrade ( tg ) )
return true ;
tg = sq_to_tg ( tg - > service_queue . parent_sq ) ;
if ( ! tg | | ! tg_to_blkg ( tg ) - > parent )
return false ;
}
return false ;
}
static bool throtl_can_upgrade ( struct throtl_data * td ,
struct throtl_grp * this_tg )
{
struct cgroup_subsys_state * pos_css ;
struct blkcg_gq * blkg ;
if ( td - > limit_index ! = LIMIT_LOW )
return false ;
rcu_read_lock ( ) ;
blkg_for_each_descendant_post ( blkg , pos_css , td - > queue - > root_blkg ) {
struct throtl_grp * tg = blkg_to_tg ( blkg ) ;
if ( tg = = this_tg )
continue ;
if ( ! list_empty ( & tg_to_blkg ( tg ) - > blkcg - > css . children ) )
continue ;
if ( ! throtl_hierarchy_can_upgrade ( tg ) ) {
rcu_read_unlock ( ) ;
return false ;
}
}
rcu_read_unlock ( ) ;
return true ;
}
static void throtl_upgrade_state ( struct throtl_data * td )
{
struct cgroup_subsys_state * pos_css ;
struct blkcg_gq * blkg ;
td - > limit_index = LIMIT_MAX ;
rcu_read_lock ( ) ;
blkg_for_each_descendant_post ( blkg , pos_css , td - > queue - > root_blkg ) {
struct throtl_grp * tg = blkg_to_tg ( blkg ) ;
struct throtl_service_queue * sq = & tg - > service_queue ;
tg - > disptime = jiffies - 1 ;
throtl_select_dispatch ( sq ) ;
throtl_schedule_next_dispatch ( sq , false ) ;
}
rcu_read_unlock ( ) ;
throtl_select_dispatch ( & td - > service_queue ) ;
throtl_schedule_next_dispatch ( & td - > service_queue , false ) ;
queue_work ( kthrotld_workqueue , & td - > dispatch_work ) ;
}
bool blk_throtl_bio ( struct request_queue * q , struct blkcg_gq * blkg ,
bool blk_throtl_bio ( struct request_queue * q , struct blkcg_gq * blkg ,
struct bio * bio )
struct bio * bio )
{
{
@ -1544,14 +1630,20 @@ bool blk_throtl_bio(struct request_queue *q, struct blkcg_gq *blkg,
sq = & tg - > service_queue ;
sq = & tg - > service_queue ;
again :
while ( true ) {
while ( true ) {
/* throtl is FIFO - if bios are already queued, should queue */
/* throtl is FIFO - if bios are already queued, should queue */
if ( sq - > nr_queued [ rw ] )
if ( sq - > nr_queued [ rw ] )
break ;
break ;
/* if above limits, break to queue */
/* if above limits, break to queue */
if ( ! tg_may_dispatch ( tg , bio , NULL ) )
if ( ! tg_may_dispatch ( tg , bio , NULL ) ) {
if ( throtl_can_upgrade ( tg - > td , tg ) ) {
throtl_upgrade_state ( tg - > td ) ;
goto again ;
}
break ;
break ;
}
/* within limits, let's charge and dispatch directly */
/* within limits, let's charge and dispatch directly */
throtl_charge_bio ( tg , bio ) ;
throtl_charge_bio ( tg , bio ) ;