All of lore.kernel.org
 help / color / mirror / Atom feed
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

  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.