mirror of https://gitee.com/openkylin/linux.git
raid5: fix incorrectly counter of conf->empty_inactive_list_nr
The counter conf->empty_inactive_list_nr is only used for determine if the raid5 is congested which is deal with in function raid5_congested(). It was increased in get_free_stripe() when conf->inactive_list got to be empty and decreased in release_inactive_stripe_list() when splice temp_inactive_list to conf->inactive_list. However, this may have a problem when raid5_get_active_stripe or stripe_add_to_batch_list was called, because these two functions may call list_del_init(&sh->lru) to delete sh from "conf->inactive_list + hash" which may cause "conf->inactive_list + hash" to be empty when atomic_inc_not_zero(&sh->count) got false. So a check should be done at these two point and increase empty_inactive_list_nr accordingly. Otherwise the counter may get to be negative number which would influence async readahead from VFS. Signed-off-by: ZhengYuan Liu <liuzhengyuan@kylinos.cn> Signed-off-by: Shaohua Li <shli@fb.com>
This commit is contained in:
parent
9b622e2bbc
commit
ff00d3b4e5
|
@ -659,6 +659,7 @@ raid5_get_active_stripe(struct r5conf *conf, sector_t sector,
|
||||||
{
|
{
|
||||||
struct stripe_head *sh;
|
struct stripe_head *sh;
|
||||||
int hash = stripe_hash_locks_hash(sector);
|
int hash = stripe_hash_locks_hash(sector);
|
||||||
|
int inc_empty_inactive_list_flag;
|
||||||
|
|
||||||
pr_debug("get_stripe, sector %llu\n", (unsigned long long)sector);
|
pr_debug("get_stripe, sector %llu\n", (unsigned long long)sector);
|
||||||
|
|
||||||
|
@ -703,7 +704,12 @@ raid5_get_active_stripe(struct r5conf *conf, sector_t sector,
|
||||||
atomic_inc(&conf->active_stripes);
|
atomic_inc(&conf->active_stripes);
|
||||||
BUG_ON(list_empty(&sh->lru) &&
|
BUG_ON(list_empty(&sh->lru) &&
|
||||||
!test_bit(STRIPE_EXPANDING, &sh->state));
|
!test_bit(STRIPE_EXPANDING, &sh->state));
|
||||||
|
inc_empty_inactive_list_flag = 0;
|
||||||
|
if (!list_empty(conf->inactive_list + hash))
|
||||||
|
inc_empty_inactive_list_flag = 1;
|
||||||
list_del_init(&sh->lru);
|
list_del_init(&sh->lru);
|
||||||
|
if (list_empty(conf->inactive_list + hash) && inc_empty_inactive_list_flag)
|
||||||
|
atomic_inc(&conf->empty_inactive_list_nr);
|
||||||
if (sh->group) {
|
if (sh->group) {
|
||||||
sh->group->stripes_cnt--;
|
sh->group->stripes_cnt--;
|
||||||
sh->group = NULL;
|
sh->group = NULL;
|
||||||
|
@ -762,6 +768,7 @@ static void stripe_add_to_batch_list(struct r5conf *conf, struct stripe_head *sh
|
||||||
sector_t head_sector, tmp_sec;
|
sector_t head_sector, tmp_sec;
|
||||||
int hash;
|
int hash;
|
||||||
int dd_idx;
|
int dd_idx;
|
||||||
|
int inc_empty_inactive_list_flag;
|
||||||
|
|
||||||
/* Don't cross chunks, so stripe pd_idx/qd_idx is the same */
|
/* Don't cross chunks, so stripe pd_idx/qd_idx is the same */
|
||||||
tmp_sec = sh->sector;
|
tmp_sec = sh->sector;
|
||||||
|
@ -779,7 +786,12 @@ static void stripe_add_to_batch_list(struct r5conf *conf, struct stripe_head *sh
|
||||||
atomic_inc(&conf->active_stripes);
|
atomic_inc(&conf->active_stripes);
|
||||||
BUG_ON(list_empty(&head->lru) &&
|
BUG_ON(list_empty(&head->lru) &&
|
||||||
!test_bit(STRIPE_EXPANDING, &head->state));
|
!test_bit(STRIPE_EXPANDING, &head->state));
|
||||||
|
inc_empty_inactive_list_flag = 0;
|
||||||
|
if (!list_empty(conf->inactive_list + hash))
|
||||||
|
inc_empty_inactive_list_flag = 1;
|
||||||
list_del_init(&head->lru);
|
list_del_init(&head->lru);
|
||||||
|
if (list_empty(conf->inactive_list + hash) && inc_empty_inactive_list_flag)
|
||||||
|
atomic_inc(&conf->empty_inactive_list_nr);
|
||||||
if (head->group) {
|
if (head->group) {
|
||||||
head->group->stripes_cnt--;
|
head->group->stripes_cnt--;
|
||||||
head->group = NULL;
|
head->group = NULL;
|
||||||
|
|
Loading…
Reference in New Issue