From: kernel test robot <lkp@intel.com>
To: Alireza Haghdoost via B4 Relay <devnull+haghdoost.uber.com@kernel.org>
Cc: oe-kbuild-all@lists.linux.dev
Subject: Re: [PATCH RFC] memcg: add per-cgroup dirty page controls (dirty_ratio, dirty_min)
Date: Sun, 3 May 2026 16:59:20 +0800 [thread overview]
Message-ID: <202605031656.ByQM5ZN9-lkp@intel.com> (raw)
In-Reply-To: <20260501-rfc-memcg-dirty-v1-v1-1-9a8c80036ec1@uber.com>
Hi Alireza,
[This is a private test report for your RFC patch.]
kernel test robot noticed the following build errors:
[auto build test ERROR on 254f49634ee16a731174d2ae34bc50bd5f45e731]
url: https://github.com/intel-lab-lkp/linux/commits/Alireza-Haghdoost-via-B4-Relay/memcg-add-per-cgroup-dirty-page-controls-dirty_ratio-dirty_min/20260502-235916
base: 254f49634ee16a731174d2ae34bc50bd5f45e731
patch link: https://lore.kernel.org/r/20260501-rfc-memcg-dirty-v1-v1-1-9a8c80036ec1%40uber.com
patch subject: [PATCH RFC] memcg: add per-cgroup dirty page controls (dirty_ratio, dirty_min)
config: openrisc-allnoconfig (https://download.01.org/0day-ci/archive/20260503/202605031656.ByQM5ZN9-lkp@intel.com/config)
compiler: or1k-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260503/202605031656.ByQM5ZN9-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605031656.ByQM5ZN9-lkp@intel.com/
All errors (new ones prefixed by >>):
include/asm-generic/rwonce.h:36:28: note: in expansion of macro '__native_word'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~
include/asm-generic/rwonce.h:49:9: note: in expansion of macro 'compiletime_assert_rwonce_type'
49 | compiletime_assert_rwonce_type(x); \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page-writeback.c:428:25: note: in expansion of macro 'READ_ONCE'
428 | READ_ONCE(memcg->dirty_ratio) : 0;
| ^~~~~~~~~
mm/page-writeback.c:428:40: error: invalid use of undefined type 'struct mem_cgroup'
428 | READ_ONCE(memcg->dirty_ratio) : 0;
| ^~
include/linux/compiler_types.h:679:23: note: in definition of macro '__compiletime_assert'
679 | if (!(condition)) \
| ^~~~~~~~~
include/linux/compiler_types.h:699:9: note: in expansion of macro '_compiletime_assert'
699 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:9: note: in expansion of macro 'compiletime_assert'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:28: note: in expansion of macro '__native_word'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~
include/asm-generic/rwonce.h:49:9: note: in expansion of macro 'compiletime_assert_rwonce_type'
49 | compiletime_assert_rwonce_type(x); \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page-writeback.c:428:25: note: in expansion of macro 'READ_ONCE'
428 | READ_ONCE(memcg->dirty_ratio) : 0;
| ^~~~~~~~~
mm/page-writeback.c:428:40: error: invalid use of undefined type 'struct mem_cgroup'
428 | READ_ONCE(memcg->dirty_ratio) : 0;
| ^~
include/linux/compiler_types.h:679:23: note: in definition of macro '__compiletime_assert'
679 | if (!(condition)) \
| ^~~~~~~~~
include/linux/compiler_types.h:699:9: note: in expansion of macro '_compiletime_assert'
699 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:9: note: in expansion of macro 'compiletime_assert'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:28: note: in expansion of macro '__native_word'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~
include/asm-generic/rwonce.h:49:9: note: in expansion of macro 'compiletime_assert_rwonce_type'
49 | compiletime_assert_rwonce_type(x); \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page-writeback.c:428:25: note: in expansion of macro 'READ_ONCE'
428 | READ_ONCE(memcg->dirty_ratio) : 0;
| ^~~~~~~~~
mm/page-writeback.c:428:40: error: invalid use of undefined type 'struct mem_cgroup'
428 | READ_ONCE(memcg->dirty_ratio) : 0;
| ^~
include/linux/compiler_types.h:679:23: note: in definition of macro '__compiletime_assert'
679 | if (!(condition)) \
| ^~~~~~~~~
include/linux/compiler_types.h:699:9: note: in expansion of macro '_compiletime_assert'
699 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:9: note: in expansion of macro 'compiletime_assert'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:49:9: note: in expansion of macro 'compiletime_assert_rwonce_type'
49 | compiletime_assert_rwonce_type(x); \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page-writeback.c:428:25: note: in expansion of macro 'READ_ONCE'
428 | READ_ONCE(memcg->dirty_ratio) : 0;
| ^~~~~~~~~
mm/page-writeback.c:428:40: error: invalid use of undefined type 'struct mem_cgroup'
428 | READ_ONCE(memcg->dirty_ratio) : 0;
| ^~
include/linux/compiler_types.h:635:53: note: in definition of macro '__unqual_scalar_typeof'
635 | #define __unqual_scalar_typeof(x) __typeof_unqual__(x)
| ^
include/asm-generic/rwonce.h:50:9: note: in expansion of macro '__READ_ONCE'
50 | __READ_ONCE(x); \
| ^~~~~~~~~~~
mm/page-writeback.c:428:25: note: in expansion of macro 'READ_ONCE'
428 | READ_ONCE(memcg->dirty_ratio) : 0;
| ^~~~~~~~~
In file included from ./arch/openrisc/include/generated/asm/rwonce.h:1,
from include/linux/compiler.h:369,
from include/linux/array_size.h:5,
from include/linux/kernel.h:16,
from mm/page-writeback.c:15:
mm/page-writeback.c:428:40: error: invalid use of undefined type 'struct mem_cgroup'
428 | READ_ONCE(memcg->dirty_ratio) : 0;
| ^~
include/asm-generic/rwonce.h:44:73: note: in definition of macro '__READ_ONCE'
44 | #define __READ_ONCE(x) (*(const volatile __unqual_scalar_typeof(x) *)&(x))
| ^
mm/page-writeback.c:428:25: note: in expansion of macro 'READ_ONCE'
428 | READ_ONCE(memcg->dirty_ratio) : 0;
| ^~~~~~~~~
mm/page-writeback.c: In function 'balance_dirty_pages':
mm/page-writeback.c:1912:33: error: implicit declaration of function 'mem_cgroup_from_task'; did you mean 'mem_cgroup_from_css'? [-Wimplicit-function-declaration]
1912 | mem_cgroup_from_task(current);
| ^~~~~~~~~~~~~~~~~~~~
| mem_cgroup_from_css
>> mm/page-writeback.c:1912:33: error: initialization of 'struct mem_cgroup *' from 'int' makes pointer from integer without a cast [-Wint-conversion]
mm/page-writeback.c:1915:63: error: invalid use of undefined type 'struct mem_cgroup'
1915 | cg_dirty_min = READ_ONCE(memcg->dirty_min);
| ^~
include/linux/compiler_types.h:679:23: note: in definition of macro '__compiletime_assert'
679 | if (!(condition)) \
| ^~~~~~~~~
include/linux/compiler_types.h:699:9: note: in expansion of macro '_compiletime_assert'
699 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:9: note: in expansion of macro 'compiletime_assert'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:28: note: in expansion of macro '__native_word'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~
include/asm-generic/rwonce.h:49:9: note: in expansion of macro 'compiletime_assert_rwonce_type'
49 | compiletime_assert_rwonce_type(x); \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page-writeback.c:1915:48: note: in expansion of macro 'READ_ONCE'
1915 | cg_dirty_min = READ_ONCE(memcg->dirty_min);
| ^~~~~~~~~
mm/page-writeback.c:1915:63: error: invalid use of undefined type 'struct mem_cgroup'
1915 | cg_dirty_min = READ_ONCE(memcg->dirty_min);
| ^~
include/linux/compiler_types.h:679:23: note: in definition of macro '__compiletime_assert'
679 | if (!(condition)) \
| ^~~~~~~~~
include/linux/compiler_types.h:699:9: note: in expansion of macro '_compiletime_assert'
699 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:9: note: in expansion of macro 'compiletime_assert'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:28: note: in expansion of macro '__native_word'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~
include/asm-generic/rwonce.h:49:9: note: in expansion of macro 'compiletime_assert_rwonce_type'
49 | compiletime_assert_rwonce_type(x); \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page-writeback.c:1915:48: note: in expansion of macro 'READ_ONCE'
1915 | cg_dirty_min = READ_ONCE(memcg->dirty_min);
| ^~~~~~~~~
mm/page-writeback.c:1915:63: error: invalid use of undefined type 'struct mem_cgroup'
1915 | cg_dirty_min = READ_ONCE(memcg->dirty_min);
| ^~
include/linux/compiler_types.h:679:23: note: in definition of macro '__compiletime_assert'
679 | if (!(condition)) \
| ^~~~~~~~~
include/linux/compiler_types.h:699:9: note: in expansion of macro '_compiletime_assert'
699 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:9: note: in expansion of macro 'compiletime_assert'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:28: note: in expansion of macro '__native_word'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~
include/asm-generic/rwonce.h:49:9: note: in expansion of macro 'compiletime_assert_rwonce_type'
49 | compiletime_assert_rwonce_type(x); \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page-writeback.c:1915:48: note: in expansion of macro 'READ_ONCE'
1915 | cg_dirty_min = READ_ONCE(memcg->dirty_min);
| ^~~~~~~~~
mm/page-writeback.c:1915:63: error: invalid use of undefined type 'struct mem_cgroup'
1915 | cg_dirty_min = READ_ONCE(memcg->dirty_min);
| ^~
include/linux/compiler_types.h:679:23: note: in definition of macro '__compiletime_assert'
679 | if (!(condition)) \
| ^~~~~~~~~
include/linux/compiler_types.h:699:9: note: in expansion of macro '_compiletime_assert'
699 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:9: note: in expansion of macro 'compiletime_assert'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:28: note: in expansion of macro '__native_word'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~
include/asm-generic/rwonce.h:49:9: note: in expansion of macro 'compiletime_assert_rwonce_type'
49 | compiletime_assert_rwonce_type(x); \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page-writeback.c:1915:48: note: in expansion of macro 'READ_ONCE'
1915 | cg_dirty_min = READ_ONCE(memcg->dirty_min);
| ^~~~~~~~~
mm/page-writeback.c:1915:63: error: invalid use of undefined type 'struct mem_cgroup'
1915 | cg_dirty_min = READ_ONCE(memcg->dirty_min);
| ^~
include/linux/compiler_types.h:679:23: note: in definition of macro '__compiletime_assert'
679 | if (!(condition)) \
| ^~~~~~~~~
include/linux/compiler_types.h:699:9: note: in expansion of macro '_compiletime_assert'
699 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| ^~~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:36:9: note: in expansion of macro 'compiletime_assert'
36 | compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
| ^~~~~~~~~~~~~~~~~~
include/asm-generic/rwonce.h:49:9: note: in expansion of macro 'compiletime_assert_rwonce_type'
49 | compiletime_assert_rwonce_type(x); \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page-writeback.c:1915:48: note: in expansion of macro 'READ_ONCE'
vim +1912 mm/page-writeback.c
1853
1854 /*
1855 * balance_dirty_pages() must be called by processes which are generating dirty
1856 * data. It looks at the number of dirty pages in the machine and will force
1857 * the caller to wait once crossing the (background_thresh + dirty_thresh) / 2.
1858 * If we're over `background_thresh' then the writeback threads are woken to
1859 * perform some writeout.
1860 */
1861 static int balance_dirty_pages(struct bdi_writeback *wb,
1862 unsigned long pages_dirtied, unsigned int flags)
1863 {
1864 struct dirty_throttle_control gdtc_stor = { GDTC_INIT(wb) };
1865 struct dirty_throttle_control mdtc_stor = { MDTC_INIT(wb, &gdtc_stor) };
1866 struct dirty_throttle_control * const gdtc = &gdtc_stor;
1867 struct dirty_throttle_control * const mdtc = mdtc_valid(&mdtc_stor) ?
1868 &mdtc_stor : NULL;
1869 struct dirty_throttle_control *sdtc;
1870 unsigned long nr_dirty;
1871 long period;
1872 long pause;
1873 long max_pause;
1874 long min_pause;
1875 int nr_dirtied_pause;
1876 unsigned long task_ratelimit;
1877 unsigned long dirty_ratelimit;
1878 struct backing_dev_info *bdi = wb->bdi;
1879 bool strictlimit = bdi->capabilities & BDI_CAP_STRICTLIMIT;
1880 unsigned long start_time = jiffies;
1881 int ret = 0;
1882
1883 for (;;) {
1884 unsigned long cg_dirty_min = 0;
1885 unsigned long cg_dirty_pages = 0;
1886 unsigned long now = jiffies;
1887
1888 nr_dirty = global_node_page_state(NR_FILE_DIRTY);
1889
1890 balance_domain_limits(gdtc, strictlimit);
1891
1892 /*
1893 * Under RCU, snapshot the current memcg's memory.dirty_min
1894 * reservation. When it is non-zero, also snapshot the
1895 * memcg-wide dirty backlog. These feed the per-writer
1896 * dirty_min bypass below; the dirty_ratio clamp itself
1897 * is applied inside domain_dirty_limits() keyed on
1898 * wb->memcg_css so balance_dirty_pages(),
1899 * wb_over_bg_thresh() (flusher kworker context), and
1900 * cgwb_calc_thresh() all see a consistent clamped
1901 * threshold.
1902 *
1903 * rcu_read_lock() is held only for the __rcu dereference
1904 * of current->cgroups; the memcg pointer does not escape
1905 * the critical section. The counter read matches
1906 * domain_dirty_avail(mdtc, true) so the bypass compares
1907 * the same dirty+in-flight backlog the global path uses.
1908 */
1909 rcu_read_lock();
1910 {
1911 struct mem_cgroup *memcg =
> 1912 mem_cgroup_from_task(current);
1913
1914 if (memcg) {
1915 cg_dirty_min = READ_ONCE(memcg->dirty_min);
1916 if (cg_dirty_min)
1917 cg_dirty_pages =
1918 memcg_page_state(memcg,
1919 NR_FILE_DIRTY) +
1920 memcg_page_state(memcg,
1921 NR_WRITEBACK);
1922 }
1923 }
1924 rcu_read_unlock();
1925
1926 if (mdtc) {
1927 /*
1928 * For !root memcg, repeat the same three-step
1929 * sequence as balance_domain_limits(gdtc):
1930 * avail -> limits -> freerun. We inline it here
1931 * so we can insert the mdtc->dirty override
1932 * between step 2 (domain_dirty_limits, which
1933 * publishes the per-memcg dirty_ratio clamp on
1934 * cg_dirty_cap) and step 3 (domain_dirty_freerun,
1935 * which consumes mdtc->dirty along with
1936 * thresh/bg_thresh).
1937 */
1938 domain_dirty_avail(mdtc, true);
1939 domain_dirty_limits(mdtc);
1940
1941 /*
1942 * When the dirty_ratio clamp engaged, replace the
1943 * per-wb dirty count from mem_cgroup_wb_stats()
1944 * with the memcg-wide NR_FILE_DIRTY + NR_WRITEBACK
1945 * sum so freerun, the setpoint, and the rate-limit
1946 * smoothing see the true memcg backlog instead of
1947 * the subset that has migrated to this cgwb (cgwb
1948 * migration is lazy and can lag by many seconds),
1949 * and so a burst of buffered writes cannot silently
1950 * bypass the clamp by shifting pages from
1951 * NR_FILE_DIRTY into NR_WRITEBACK.
1952 *
1953 * Keyed on wb->memcg_css to match the clamp itself.
1954 * The cgwb holds a css reference, so the memcg
1955 * pointer is stable without additional locking.
1956 *
1957 * Caveat: memcg_page_state() aggregates across ALL
1958 * backing devices owned by this memcg, while mdtc
1959 * is scoped to one wb. A writer to a fast BDI may
1960 * observe backlog accumulated on slow BDIs in the
1961 * same memcg and throttle more than strictly needed.
1962 * Accepted for v1; the alternative (summing per-wb
1963 * dirty across the memcg's cgwbs) walks the cgwb
1964 * list under RCU on a hot path.
1965 */
1966 if (mdtc->cg_dirty_cap != PAGE_COUNTER_MAX) {
1967 struct mem_cgroup *wb_memcg =
1968 mem_cgroup_from_css(mdtc->wb->memcg_css);
1969
1970 if (wb_memcg)
1971 mdtc->dirty =
1972 memcg_page_state(wb_memcg,
1973 NR_FILE_DIRTY) +
1974 memcg_page_state(wb_memcg,
1975 NR_WRITEBACK);
1976 }
1977
1978 domain_dirty_freerun(mdtc, strictlimit);
1979 }
1980
1981 if (nr_dirty > gdtc->bg_thresh && !writeback_in_progress(wb))
1982 wb_start_background_writeback(wb);
1983
1984 /*
1985 * dirty_min bypass: when the current memcg's dirty+in-flight
1986 * backlog is below its memory.dirty_min reservation, let the
1987 * writer proceed without throttling. This check must live
1988 * outside the if (mdtc) block because a writer's file may not
1989 * yet have been migrated to a cgwb; without cgwb, mdtc is NULL
1990 * and the per-memcg block above is skipped entirely.
1991 *
1992 * cg_dirty_min and cg_dirty_pages come from the per-iteration
1993 * snapshot taken above under rcu_read_lock; both are stored
1994 * in pages (page_counter_memparse converts bytes -> pages for
1995 * dirty_min), so no unit conversion is needed.
1996 */
1997 if (cg_dirty_min && cg_dirty_pages < cg_dirty_min)
1998 goto free_running;
1999
2000 /*
2001 * If memcg domain is in effect, @dirty should be under
2002 * both global and memcg freerun ceilings.
2003 */
2004 if (gdtc->freerun && (!mdtc || mdtc->freerun)) {
2005 unsigned long intv;
2006 unsigned long m_intv;
2007
2008 free_running:
2009 intv = domain_poll_intv(gdtc, strictlimit);
2010 m_intv = ULONG_MAX;
2011
2012 current->dirty_paused_when = now;
2013 current->nr_dirtied = 0;
2014 if (mdtc)
2015 m_intv = domain_poll_intv(mdtc, strictlimit);
2016 current->nr_dirtied_pause = min(intv, m_intv);
2017 break;
2018 }
2019
2020 /*
2021 * Unconditionally start background writeback if it's not
2022 * already in progress. We need to do this because the global
2023 * dirty threshold check above (nr_dirty > gdtc->bg_thresh)
2024 * doesn't account for these cases:
2025 *
2026 * a) strictlimit BDIs: throttling is calculated using per-wb
2027 * thresholds. The per-wb threshold can be exceeded even when
2028 * nr_dirty < gdtc->bg_thresh
2029 *
2030 * b) memcg-based throttling: memcg uses its own dirty count and
2031 * thresholds and can trigger throttling even when global
2032 * nr_dirty < gdtc->bg_thresh
2033 *
2034 * Writeback needs to be started else the writer stalls in the
2035 * throttle loop waiting for dirty pages to be written back
2036 * while no writeback is running.
2037 */
2038 if (unlikely(!writeback_in_progress(wb)))
2039 wb_start_background_writeback(wb);
2040
2041 mem_cgroup_flush_foreign(wb);
2042
2043 /*
2044 * Calculate global domain's pos_ratio and select the
2045 * global dtc by default.
2046 */
2047 balance_wb_limits(gdtc, strictlimit);
2048 if (gdtc->freerun)
2049 goto free_running;
2050 sdtc = gdtc;
2051
2052 if (mdtc) {
2053 /*
2054 * If memcg domain is in effect, calculate its
2055 * pos_ratio. @wb should satisfy constraints from
2056 * both global and memcg domains. Choose the one
2057 * w/ lower pos_ratio.
2058 */
2059 balance_wb_limits(mdtc, strictlimit);
2060 if (mdtc->freerun)
2061 goto free_running;
2062 if (mdtc->pos_ratio < gdtc->pos_ratio)
2063 sdtc = mdtc;
2064 }
2065
2066 wb->dirty_exceeded = gdtc->dirty_exceeded ||
2067 (mdtc && mdtc->dirty_exceeded);
2068 if (time_is_before_jiffies(READ_ONCE(wb->bw_time_stamp) +
2069 BANDWIDTH_INTERVAL))
2070 __wb_update_bandwidth(gdtc, mdtc, true);
2071
2072 /* throttle according to the chosen dtc */
2073 dirty_ratelimit = READ_ONCE(wb->dirty_ratelimit);
2074 task_ratelimit = ((u64)dirty_ratelimit * sdtc->pos_ratio) >>
2075 RATELIMIT_CALC_SHIFT;
2076 max_pause = wb_max_pause(wb, sdtc->wb_dirty);
2077 min_pause = wb_min_pause(wb, max_pause,
2078 task_ratelimit, dirty_ratelimit,
2079 &nr_dirtied_pause);
2080
2081 if (unlikely(task_ratelimit == 0)) {
2082 period = max_pause;
2083 pause = max_pause;
2084 goto pause;
2085 }
2086 period = HZ * pages_dirtied / task_ratelimit;
2087 pause = period;
2088 if (current->dirty_paused_when)
2089 pause -= now - current->dirty_paused_when;
2090 /*
2091 * For less than 1s think time (ext3/4 may block the dirtier
2092 * for up to 800ms from time to time on 1-HDD; so does xfs,
2093 * however at much less frequency), try to compensate it in
2094 * future periods by updating the virtual time; otherwise just
2095 * do a reset, as it may be a light dirtier.
2096 */
2097 if (pause < min_pause) {
2098 trace_balance_dirty_pages(wb,
2099 sdtc,
2100 dirty_ratelimit,
2101 task_ratelimit,
2102 pages_dirtied,
2103 period,
2104 min(pause, 0L),
2105 start_time);
2106 if (pause < -HZ) {
2107 current->dirty_paused_when = now;
2108 current->nr_dirtied = 0;
2109 } else if (period) {
2110 current->dirty_paused_when += period;
2111 current->nr_dirtied = 0;
2112 } else if (current->nr_dirtied_pause <= pages_dirtied)
2113 current->nr_dirtied_pause += pages_dirtied;
2114 break;
2115 }
2116 if (unlikely(pause > max_pause)) {
2117 /* for occasional dropped task_ratelimit */
2118 now += min(pause - max_pause, max_pause);
2119 pause = max_pause;
2120 }
2121
2122 pause:
2123 trace_balance_dirty_pages(wb,
2124 sdtc,
2125 dirty_ratelimit,
2126 task_ratelimit,
2127 pages_dirtied,
2128 period,
2129 pause,
2130 start_time);
2131 if (flags & BDP_ASYNC) {
2132 ret = -EAGAIN;
2133 break;
2134 }
2135 __set_current_state(TASK_KILLABLE);
2136 bdi->last_bdp_sleep = jiffies;
2137 io_schedule_timeout(pause);
2138
2139 current->dirty_paused_when = now + pause;
2140 current->nr_dirtied = 0;
2141 current->nr_dirtied_pause = nr_dirtied_pause;
2142
2143 /*
2144 * This is typically equal to (dirty < thresh) and can also
2145 * keep "1000+ dd on a slow USB stick" under control.
2146 */
2147 if (task_ratelimit)
2148 break;
2149
2150 /*
2151 * In the case of an unresponsive NFS server and the NFS dirty
2152 * pages exceeds dirty_thresh, give the other good wb's a pipe
2153 * to go through, so that tasks on them still remain responsive.
2154 *
2155 * In theory 1 page is enough to keep the consumer-producer
2156 * pipe going: the flusher cleans 1 page => the task dirties 1
2157 * more page. However wb_dirty has accounting errors. So use
2158 * the larger and more IO friendly wb_stat_error.
2159 */
2160 if (sdtc->wb_dirty <= wb_stat_error())
2161 break;
2162
2163 if (fatal_signal_pending(current))
2164 break;
2165 }
2166 return ret;
2167 }
2168
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
next prev parent reply other threads:[~2026-05-03 8:59 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-01 22:28 [PATCH RFC] memcg: add per-cgroup dirty page controls (dirty_ratio, dirty_min) Alireza Haghdoost
2026-05-01 22:28 ` Alireza Haghdoost via B4 Relay
2026-05-03 8:59 ` kernel test robot [this message]
2026-05-03 9:55 ` kernel test robot
2026-05-06 14:21 ` Jan Kara
2026-05-14 4:10 ` Alireza Haghdoost
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=202605031656.ByQM5ZN9-lkp@intel.com \
--to=lkp@intel.com \
--cc=devnull+haghdoost.uber.com@kernel.org \
--cc=oe-kbuild-all@lists.linux.dev \
/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.