| From 62a584fe05eef1f80ed49a286a29328f1a224fb9 Mon Sep 17 00:00:00 2001 |
| From: Tejun Heo <tj@kernel.org> |
| Date: Fri, 27 May 2016 14:34:46 -0400 |
| Subject: writeback: use higher precision calculation in domain_dirty_limits() |
| |
| From: Tejun Heo <tj@kernel.org> |
| |
| commit 62a584fe05eef1f80ed49a286a29328f1a224fb9 upstream. |
| |
| As vm.dirty_[background_]bytes can't be applied verbatim to multiple |
| cgroup writeback domains, they get converted to percentages in |
| domain_dirty_limits() and applied the same way as |
| vm.dirty_[background]ratio. However, if the specified bytes is lower |
| than 1% of available memory, the calculated ratios become zero and the |
| writeback domain gets throttled constantly. |
| |
| Fix it by using per-PAGE_SIZE instead of percentage for ratio |
| calculations. Also, the updated DIV_ROUND_UP() usages now should |
| yield 1/4096 (0.0244%) as the minimum ratio as long as the specified |
| bytes are above zero. |
| |
| Signed-off-by: Tejun Heo <tj@kernel.org> |
| Reported-by: Miao Xie <miaoxie@huawei.com> |
| Link: http://lkml.kernel.org/g/57333E75.3080309@huawei.com |
| Fixes: 9fc3a43e1757 ("writeback: separate out domain_dirty_limits()") |
| Reviewed-by: Jan Kara <jack@suse.cz> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| Adjusted comment based on Jan's suggestion. |
| Signed-off-by: Jens Axboe <axboe@fb.com> |
| |
| --- |
| mm/page-writeback.c | 21 ++++++++++++--------- |
| 1 file changed, 12 insertions(+), 9 deletions(-) |
| |
| --- a/mm/page-writeback.c |
| +++ b/mm/page-writeback.c |
| @@ -359,8 +359,9 @@ static void domain_dirty_limits(struct d |
| struct dirty_throttle_control *gdtc = mdtc_gdtc(dtc); |
| unsigned long bytes = vm_dirty_bytes; |
| unsigned long bg_bytes = dirty_background_bytes; |
| - unsigned long ratio = vm_dirty_ratio; |
| - unsigned long bg_ratio = dirty_background_ratio; |
| + /* convert ratios to per-PAGE_SIZE for higher precision */ |
| + unsigned long ratio = (vm_dirty_ratio * PAGE_SIZE) / 100; |
| + unsigned long bg_ratio = (dirty_background_ratio * PAGE_SIZE) / 100; |
| unsigned long thresh; |
| unsigned long bg_thresh; |
| struct task_struct *tsk; |
| @@ -372,26 +373,28 @@ static void domain_dirty_limits(struct d |
| /* |
| * The byte settings can't be applied directly to memcg |
| * domains. Convert them to ratios by scaling against |
| - * globally available memory. |
| + * globally available memory. As the ratios are in |
| + * per-PAGE_SIZE, they can be obtained by dividing bytes by |
| + * number of pages. |
| */ |
| if (bytes) |
| - ratio = min(DIV_ROUND_UP(bytes, PAGE_SIZE) * 100 / |
| - global_avail, 100UL); |
| + ratio = min(DIV_ROUND_UP(bytes, global_avail), |
| + PAGE_SIZE); |
| if (bg_bytes) |
| - bg_ratio = min(DIV_ROUND_UP(bg_bytes, PAGE_SIZE) * 100 / |
| - global_avail, 100UL); |
| + bg_ratio = min(DIV_ROUND_UP(bg_bytes, global_avail), |
| + PAGE_SIZE); |
| bytes = bg_bytes = 0; |
| } |
| |
| if (bytes) |
| thresh = DIV_ROUND_UP(bytes, PAGE_SIZE); |
| else |
| - thresh = (ratio * available_memory) / 100; |
| + thresh = (ratio * available_memory) / PAGE_SIZE; |
| |
| if (bg_bytes) |
| bg_thresh = DIV_ROUND_UP(bg_bytes, PAGE_SIZE); |
| else |
| - bg_thresh = (bg_ratio * available_memory) / 100; |
| + bg_thresh = (bg_ratio * available_memory) / PAGE_SIZE; |
| |
| if (bg_thresh >= thresh) |
| bg_thresh = thresh / 2; |