]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
mm: fix div by zero in bdi_ratio_from_pages
authorStefan Roesch <shr@devkernel.io>
Sat, 4 Jan 2025 01:20:37 +0000 (17:20 -0800)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 13 Jan 2025 03:03:36 +0000 (19:03 -0800)
During testing it has been detected, that it is possible to get div by
zero error in bdi_set_min_bytes.  The error is caused by the function
bdi_ratio_from_pages().  bdi_ratio_from_pages() calls global_dirty_limits.
If the dirty threshold is 0, the div by zero is raised.  This can happen
if the root user is setting:

echo 0 > /proc/sys/vm/dirty_ratio

The following is a test case:

echo 0 > /proc/sys/vm/dirty_ratio
cd /sys/class/bdi/<device>
echo 1 > strict_limit
echo 8192 > min_bytes

==> error is raised.

The problem is addressed by returning -EINVAL if dirty_ratio or
dirty_bytes is set to 0.

[shr@devkernel.io: check for -EINVAL in bdi_set_min_bytes() and bdi_set_max_bytes()]
Link: https://lkml.kernel.org/r/20250108014723.166637-1-shr@devkernel.io
[shr@devkernel.io: v3]
Link: https://lkml.kernel.org/r/20250109063411.6591-1-shr@devkernel.io
Link: https://lkml.kernel.org/r/20250104012037.159386-1-shr@devkernel.io
Signed-off-by: Stefan Roesch <shr@devkernel.io>
Reported-by: cheung wall <zzqq0103.hey@gmail.com>
Closes: https://lore.kernel.org/linux-mm/87pll35yd0.fsf@devkernel.io/T/#t
Acked-by: David Hildenbrand <david@redhat.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Qiang Zhang <zzqq0103.hey@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
mm/page-writeback.c

index d213ead9567509bb8aad36ac0bb0a8a5d2fbc153..d9861e42b2bd2431e3a5538061bfe49821c13826 100644 (file)
@@ -692,6 +692,8 @@ static unsigned long bdi_ratio_from_pages(unsigned long pages)
        unsigned long ratio;
 
        global_dirty_limits(&background_thresh, &dirty_thresh);
+       if (!dirty_thresh)
+               return -EINVAL;
        ratio = div64_u64(pages * 100ULL * BDI_RATIO_SCALE, dirty_thresh);
 
        return ratio;
@@ -790,13 +792,15 @@ int bdi_set_min_bytes(struct backing_dev_info *bdi, u64 min_bytes)
 {
        int ret;
        unsigned long pages = min_bytes >> PAGE_SHIFT;
-       unsigned long min_ratio;
+       long min_ratio;
 
        ret = bdi_check_pages_limit(pages);
        if (ret)
                return ret;
 
        min_ratio = bdi_ratio_from_pages(pages);
+       if (min_ratio < 0)
+               return min_ratio;
        return __bdi_set_min_ratio(bdi, min_ratio);
 }
 
@@ -809,13 +813,15 @@ int bdi_set_max_bytes(struct backing_dev_info *bdi, u64 max_bytes)
 {
        int ret;
        unsigned long pages = max_bytes >> PAGE_SHIFT;
-       unsigned long max_ratio;
+       long max_ratio;
 
        ret = bdi_check_pages_limit(pages);
        if (ret)
                return ret;
 
        max_ratio = bdi_ratio_from_pages(pages);
+       if (max_ratio < 0)
+               return max_ratio;
        return __bdi_set_max_ratio(bdi, max_ratio);
 }