All of lore.kernel.org
 help / color / mirror / Atom feed
From: Maxim Patlasov <mpatlasov@parallels.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: riel@redhat.com, linux-kernel@vger.kernel.org, mhocko@suse.cz,
	linux-mm@kvack.org, kosaki.motohiro@jp.fujitsu.com,
	fengguang.wu@intel.com, jweiner@redhat.com
Subject: Re: [PATCH] mm/page-writeback.c: fix divide by zero in bdi_dirty_limits
Date: Mon, 14 Jul 2014 12:06:01 +0400	[thread overview]
Message-ID: <53C38F69.4070304@parallels.com> (raw)
In-Reply-To: <20140711152732.de78603744cd861497eca5dc@linux-foundation.org>

Hi Andrew,

On 07/12/2014 02:27 AM, Andrew Morton wrote:
> On Fri, 11 Jul 2014 12:18:27 +0400 Maxim Patlasov <MPatlasov@parallels.com> wrote:
>
>> Under memory pressure, it is possible for dirty_thresh, calculated by
>> global_dirty_limits() in balance_dirty_pages(), to equal zero.
> Under what circumstances?  Really small values of vm_dirty_bytes?

No, I used default settings:

vm_dirty_bytes = 0;
dirty_background_bytes = 0;
vm_dirty_ratio = 20;
dirty_background_ratio = 10;

and a simple program like main() { while(1) { p = malloc(4096); mlock(p, 
4096); } }. Of course, this triggers oom eventually, but immediately 
before oom, the system is under hard memory pressure.

>
>> Then, if
>> strictlimit is true, bdi_dirty_limits() tries to resolve the proportion:
>>
>>    bdi_bg_thresh : bdi_thresh = background_thresh : dirty_thresh
>>
>> by dividing by zero.
>>
>> ...
>>
>> --- a/mm/page-writeback.c
>> +++ b/mm/page-writeback.c
>> @@ -1306,9 +1306,9 @@ static inline void bdi_dirty_limits(struct backing_dev_info *bdi,
>>   	*bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh);
>>   
>>   	if (bdi_bg_thresh)
>> -		*bdi_bg_thresh = div_u64((u64)*bdi_thresh *
>> -					 background_thresh,
>> -					 dirty_thresh);
>> +		*bdi_bg_thresh = dirty_thresh ? div_u64((u64)*bdi_thresh *
>> +							background_thresh,
>> +							dirty_thresh) : 0;
> This introduces a peculiar discontinuity:
>
> if dirty_thresh==3, treat it as 3
> if dirty_thresh==2, treat it as 2
> if dirty_thresh==1, treat it as 1
> if dirty_thresh==0, treat it as infinity

No, the patch doesn't treat dirty_thresh==0 as infinity. In fact, in 
that case we have equation: x : 0 = 0 : 0, and the patch resolves it as 
x=0. Here is the reasoning:

1. A bdi counter is always a fraction of global one. Hence bdi_thresh is 
always not greater than dirty_thresh. So far as dirty_thresh is equal to 
zero, bdi_thresh is equal to zero too.
2. bdi_bg_thresh must be not greater than bdi_thresh because we want to 
start background process earlier than throttling it. So far as 
bdi_thresh is equal to zero, bdi_bg_thresh must be zero too.


>
> Would it not make more sense to change global_dirty_limits() to convert
> 0 to 1?  With an appropriate comment, obviously.
>
>
> Or maybe the fix lies elsewhere.  Please do tell us how this zero comes
> about.
>

Firstly let me explain where available_memory equal to one came from. 
global_dirty_limits() calculates it by calling 
global_dirtyable_memory(). The latter takes into consideration three 
global counters and a global reserve. In my case corresponding values were:

NR_INACTIVE_FILE = 0
NR_ACTIVE_FILE = 0
NR_FREE_PAGES = 7006
dirty_balance_reserve = 7959.

Consequently, "x" in global_dirtyable_memory() was equal to zero, and 
the function returned one. Now global_dirty_limits() assigns 
available_memory to one and calculates "dirty" as a fraction of 
available_memory:

     dirty = (vm_dirty_ratio * available_memory) / 100;

So far as vm_drity_ratio is lesser than 100 (it is 20 by default), dirty 
is calculated as zero.

As for your question about conversion 0 to 1, I think that bdi_thresh = 
dirty_thresh = 0 makes natural sense: we are under strong memory 
pressure, please always start background writeback and throttle process 
(even if actual number of dirty pages is low). So other parts of 
balance_dirty_pages machinery must handle zero thresholds properly.

Thanks,
Maxim

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

WARNING: multiple messages have this Message-ID (diff)
From: Maxim Patlasov <mpatlasov@parallels.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: <riel@redhat.com>, <linux-kernel@vger.kernel.org>,
	<mhocko@suse.cz>, <linux-mm@kvack.org>,
	<kosaki.motohiro@jp.fujitsu.com>, <fengguang.wu@intel.com>,
	<jweiner@redhat.com>
Subject: Re: [PATCH] mm/page-writeback.c: fix divide by zero in bdi_dirty_limits
Date: Mon, 14 Jul 2014 12:06:01 +0400	[thread overview]
Message-ID: <53C38F69.4070304@parallels.com> (raw)
In-Reply-To: <20140711152732.de78603744cd861497eca5dc@linux-foundation.org>

Hi Andrew,

On 07/12/2014 02:27 AM, Andrew Morton wrote:
> On Fri, 11 Jul 2014 12:18:27 +0400 Maxim Patlasov <MPatlasov@parallels.com> wrote:
>
>> Under memory pressure, it is possible for dirty_thresh, calculated by
>> global_dirty_limits() in balance_dirty_pages(), to equal zero.
> Under what circumstances?  Really small values of vm_dirty_bytes?

No, I used default settings:

vm_dirty_bytes = 0;
dirty_background_bytes = 0;
vm_dirty_ratio = 20;
dirty_background_ratio = 10;

and a simple program like main() { while(1) { p = malloc(4096); mlock(p, 
4096); } }. Of course, this triggers oom eventually, but immediately 
before oom, the system is under hard memory pressure.

>
>> Then, if
>> strictlimit is true, bdi_dirty_limits() tries to resolve the proportion:
>>
>>    bdi_bg_thresh : bdi_thresh = background_thresh : dirty_thresh
>>
>> by dividing by zero.
>>
>> ...
>>
>> --- a/mm/page-writeback.c
>> +++ b/mm/page-writeback.c
>> @@ -1306,9 +1306,9 @@ static inline void bdi_dirty_limits(struct backing_dev_info *bdi,
>>   	*bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh);
>>   
>>   	if (bdi_bg_thresh)
>> -		*bdi_bg_thresh = div_u64((u64)*bdi_thresh *
>> -					 background_thresh,
>> -					 dirty_thresh);
>> +		*bdi_bg_thresh = dirty_thresh ? div_u64((u64)*bdi_thresh *
>> +							background_thresh,
>> +							dirty_thresh) : 0;
> This introduces a peculiar discontinuity:
>
> if dirty_thresh==3, treat it as 3
> if dirty_thresh==2, treat it as 2
> if dirty_thresh==1, treat it as 1
> if dirty_thresh==0, treat it as infinity

No, the patch doesn't treat dirty_thresh==0 as infinity. In fact, in 
that case we have equation: x : 0 = 0 : 0, and the patch resolves it as 
x=0. Here is the reasoning:

1. A bdi counter is always a fraction of global one. Hence bdi_thresh is 
always not greater than dirty_thresh. So far as dirty_thresh is equal to 
zero, bdi_thresh is equal to zero too.
2. bdi_bg_thresh must be not greater than bdi_thresh because we want to 
start background process earlier than throttling it. So far as 
bdi_thresh is equal to zero, bdi_bg_thresh must be zero too.


>
> Would it not make more sense to change global_dirty_limits() to convert
> 0 to 1?  With an appropriate comment, obviously.
>
>
> Or maybe the fix lies elsewhere.  Please do tell us how this zero comes
> about.
>

Firstly let me explain where available_memory equal to one came from. 
global_dirty_limits() calculates it by calling 
global_dirtyable_memory(). The latter takes into consideration three 
global counters and a global reserve. In my case corresponding values were:

NR_INACTIVE_FILE = 0
NR_ACTIVE_FILE = 0
NR_FREE_PAGES = 7006
dirty_balance_reserve = 7959.

Consequently, "x" in global_dirtyable_memory() was equal to zero, and 
the function returned one. Now global_dirty_limits() assigns 
available_memory to one and calculates "dirty" as a fraction of 
available_memory:

     dirty = (vm_dirty_ratio * available_memory) / 100;

So far as vm_drity_ratio is lesser than 100 (it is 20 by default), dirty 
is calculated as zero.

As for your question about conversion 0 to 1, I think that bdi_thresh = 
dirty_thresh = 0 makes natural sense: we are under strong memory 
pressure, please always start background writeback and throttle process 
(even if actual number of dirty pages is low). So other parts of 
balance_dirty_pages machinery must handle zero thresholds properly.

Thanks,
Maxim

  reply	other threads:[~2014-07-14  8:06 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-07-11  8:18 [PATCH] mm/page-writeback.c: fix divide by zero in bdi_dirty_limits Maxim Patlasov
2014-07-11  8:18 ` Maxim Patlasov
2014-07-11 14:49 ` Rik van Riel
2014-07-11 14:49   ` Rik van Riel
2014-07-11 22:27 ` Andrew Morton
2014-07-11 22:27   ` Andrew Morton
2014-07-14  8:06   ` Maxim Patlasov [this message]
2014-07-14  8:06     ` Maxim Patlasov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=53C38F69.4070304@parallels.com \
    --to=mpatlasov@parallels.com \
    --cc=akpm@linux-foundation.org \
    --cc=fengguang.wu@intel.com \
    --cc=jweiner@redhat.com \
    --cc=kosaki.motohiro@jp.fujitsu.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mhocko@suse.cz \
    --cc=riel@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.