diff options
author | paul.szabo@sydney.edu.au <paul.szabo@sydney.edu.au> | 2013-01-20 11:02:10 +1100 |
---|---|---|
committer | Fengguang Wu <fengguang.wu@intel.com> | 2013-01-24 22:22:22 +0800 |
commit | ed84825b785ceb932af7dd5aa08614801721320b (patch) | |
tree | b3f704912b4d1496c8317c04bb86c817c4e1afcd /mm | |
parent | 10ee27a06cc8eb57f83342a8eabcb75deb872d52 (diff) | |
download | op-kernel-dev-ed84825b785ceb932af7dd5aa08614801721320b.zip op-kernel-dev-ed84825b785ceb932af7dd5aa08614801721320b.tar.gz |
Negative (setpoint-dirty) in bdi_position_ratio()
In bdi_position_ratio(), get difference (setpoint-dirty) right even when
negative. Both setpoint and dirty are unsigned long, the difference was
zero-padded thus wrongly sign-extended to s64. This issue affects all
32-bit architectures, does not affect 64-bit architectures where long
and s64 are equivalent.
In this function, dirty is between freerun and limit, the pseudo-float x
is between [-1,1], expected to be negative about half the time. With
zero-padding, instead of a small negative x we obtained a large positive
one so bdi_position_ratio() returned garbage.
Casting the difference to s64 also prevents overflow with left-shift;
though normally these numbers are small and I never observed a 32-bit
overflow there.
(This patch does not solve the PAE OOM issue.)
Paul Szabo psz@maths.usyd.edu.au http://www.maths.usyd.edu.au/u/psz/
School of Mathematics and Statistics University of Sydney Australia
Reviewed-by: Jan Kara <jack@suse.cz>
Reported-by: Paul Szabo <psz@maths.usyd.edu.au>
Reference: http://bugs.debian.org/695182
Signed-off-by: Paul Szabo <psz@maths.usyd.edu.au>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/page-writeback.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 0713bfb..1534ebd 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -692,7 +692,7 @@ static unsigned long bdi_position_ratio(struct backing_dev_info *bdi, * => fast response on large errors; small oscillation near setpoint */ setpoint = (freerun + limit) / 2; - x = div_s64((setpoint - dirty) << RATELIMIT_CALC_SHIFT, + x = div_s64(((s64)setpoint - (s64)dirty) << RATELIMIT_CALC_SHIFT, limit - setpoint + 1); pos_ratio = x; pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT; |