diff options
author | Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> | 2014-08-26 20:56:36 +0900 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-10-05 13:40:54 -0700 |
commit | 41549646bc65252c882d2c9d0314089818a38eaf (patch) | |
tree | 0c58ad6d8459dd45e949930e06788d94de437327 /ipc/shm.c | |
parent | b6e46ec9a4ace9820d1dd37387f83962d238b0b0 (diff) | |
download | linux-stable-41549646bc65252c882d2c9d0314089818a38eaf.tar.gz linux-stable-41549646bc65252c882d2c9d0314089818a38eaf.tar.bz2 linux-stable-41549646bc65252c882d2c9d0314089818a38eaf.zip |
cfq-iosched: Fix wrong children_weight calculation
commit e15693ef18e13e3e6bffe891fe140f18b8ff6d07 upstream.
cfq_group_service_tree_add() is applying new_weight at the beginning of
the function via cfq_update_group_weight().
This actually allows weight to change between adding it to and subtracting
it from children_weight, and triggers WARN_ON_ONCE() in
cfq_group_service_tree_del(), or even causes oops by divide error during
vfr calculation in cfq_group_service_tree_add().
The detailed scenario is as follows:
1. Create blkio cgroups X and Y as a child of X.
Set X's weight to 500 and perform some I/O to apply new_weight.
This X's I/O completes before starting Y's I/O.
2. Y starts I/O and cfq_group_service_tree_add() is called with Y.
3. cfq_group_service_tree_add() walks up the tree during children_weight
calculation and adds parent X's weight (500) to children_weight of root.
children_weight becomes 500.
4. Set X's weight to 1000.
5. X starts I/O and cfq_group_service_tree_add() is called with X.
6. cfq_group_service_tree_add() applies its new_weight (1000).
7. I/O of Y completes and cfq_group_service_tree_del() is called with Y.
8. I/O of X completes and cfq_group_service_tree_del() is called with X.
9. cfq_group_service_tree_del() subtracts X's weight (1000) from
children_weight of root. children_weight becomes -500.
This triggers WARN_ON_ONCE().
10. Set X's weight to 500.
11. X starts I/O and cfq_group_service_tree_add() is called with X.
12. cfq_group_service_tree_add() applies its new_weight (500) and adds it
to children_weight of root. children_weight becomes 0. Calcularion of
vfr triggers oops by divide error.
weight should be updated right before adding it to children_weight.
Reported-by: Ruki Sekiya <sekiya.ruki@lab.ntt.co.jp>
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'ipc/shm.c')
0 files changed, 0 insertions, 0 deletions