* Re: [PATCH v2 3/9] mm: remove set_page_count() from page_frag_alloc_align
@ 2022-01-02 12:18 kernel test robot
0 siblings, 0 replies; 2+ messages in thread
From: kernel test robot @ 2022-01-02 12:18 UTC (permalink / raw)
To: kbuild
[-- Attachment #1: Type: text/plain, Size: 18850 bytes --]
CC: llvm(a)lists.linux.dev
CC: kbuild-all(a)lists.01.org
In-Reply-To: <20211221150140.988298-4-pasha.tatashin@soleen.com>
References: <20211221150140.988298-4-pasha.tatashin@soleen.com>
TO: Pasha Tatashin <pasha.tatashin@soleen.com>
TO: pasha.tatashin(a)soleen.com
TO: linux-kernel(a)vger.kernel.org
TO: linux-mm(a)kvack.org
TO: linux-m68k(a)lists.linux-m68k.org
TO: anshuman.khandual(a)arm.com
TO: willy(a)infradead.org
TO: akpm(a)linux-foundation.org
TO: william.kucharski(a)oracle.com
TO: mike.kravetz(a)oracle.com
TO: vbabka(a)suse.cz
Hi Pasha,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on hnaz-mm/master]
[also build test WARNING on rostedt-trace/for-next geert-m68k/for-next linux/master linus/master v5.16-rc7 next-20211224]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Pasha-Tatashin/Hardening-page-_refcount/20211221-230439
base: https://github.com/hnaz/linux-mm master
:::::: branch date: 12 days ago
:::::: commit date: 12 days ago
config: x86_64-randconfig-c007-20211231 (https://download.01.org/0day-ci/archive/20220102/202201022054.ufnNk7Fu-lkp(a)intel.com/config)
compiler: clang version 14.0.0 (https://github.com/llvm/llvm-project 7cd109b92c72855937273a6c8ab19016fbe27d33)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/2add304c6e5eb6206507d871ccfd11349cc32586
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Pasha-Tatashin/Hardening-page-_refcount/20211221-230439
git checkout 2add304c6e5eb6206507d871ccfd11349cc32586
# save the config file to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 clang-analyzer
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
clang-analyzer warnings: (new ones prefixed by >>)
mm/page_alloc.c:5287:3: note: Taking false branch
if (unlikely(!page)) {
^
mm/page_alloc.c:5296:7: note: Assuming 'page_list' is null
if (page_list)
^~~~~~~~~
mm/page_alloc.c:5296:3: note: Taking false branch
if (page_list)
^
mm/page_alloc.c:5299:29: note: Array access (from variable 'page_array') results in a null pointer dereference
page_array[nr_populated] = page;
~~~~~~~~~~ ^
mm/page_alloc.c:5320:29: warning: Array access (from variable 'page_array') results in a null pointer dereference [clang-analyzer-core.NullDereference]
page_array[nr_populated] = page;
~~~~~~~~~~ ^
mm/page_alloc.c:5205:9: note: Assuming 'page_array' is null
while (page_array && nr_populated < nr_pages && page_array[nr_populated])
^~~~~~~~~~
mm/page_alloc.c:5205:20: note: Left side of '&&' is false
while (page_array && nr_populated < nr_pages && page_array[nr_populated])
^
mm/page_alloc.c:5209:15: note: Assuming 'nr_pages' is > 0
if (unlikely(nr_pages <= 0))
^
include/linux/compiler.h:78:42: note: expanded from macro 'unlikely'
# define unlikely(x) __builtin_expect(!!(x), 0)
^
mm/page_alloc.c:5209:2: note: Taking false branch
if (unlikely(nr_pages <= 0))
^
mm/page_alloc.c:5213:15: note: 'page_array' is null
if (unlikely(page_array && nr_pages - nr_populated == 0))
^
include/linux/compiler.h:78:42: note: expanded from macro 'unlikely'
# define unlikely(x) __builtin_expect(!!(x), 0)
^
mm/page_alloc.c:5213:26: note: Left side of '&&' is false
if (unlikely(page_array && nr_pages - nr_populated == 0))
^
mm/page_alloc.c:5213:2: note: Taking false branch
if (unlikely(page_array && nr_pages - nr_populated == 0))
^
mm/page_alloc.c:5217:6: note: Calling 'memcg_kmem_enabled'
if (memcg_kmem_enabled() && (gfp & __GFP_ACCOUNT))
^~~~~~~~~~~~~~~~~~~~
include/linux/memcontrol.h:1714:9: note: Left side of '&&' is false
return static_branch_likely(&memcg_kmem_enabled_key);
^
include/linux/jump_label.h:507:49: note: expanded from macro 'static_branch_likely'
#define static_branch_likely(x) likely_notrace(static_key_enabled(&(x)->key))
^
include/linux/jump_label.h:416:67: note: expanded from macro 'static_key_enabled'
if (!__builtin_types_compatible_p(typeof(*x), struct static_key) && \
^
include/linux/memcontrol.h:1714:9: note: Assuming the condition is true
return static_branch_likely(&memcg_kmem_enabled_key);
^
include/linux/jump_label.h:507:49: note: expanded from macro 'static_branch_likely'
#define static_branch_likely(x) likely_notrace(static_key_enabled(&(x)->key))
~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
include/linux/jump_label.h:420:2: note: expanded from macro 'static_key_enabled'
static_key_count((struct static_key *)x) > 0; \
^
include/linux/compiler.h:79:35: note: expanded from macro 'likely_notrace'
# define likely_notrace(x) likely(x)
~~~~~~~^~
include/linux/compiler.h:77:40: note: expanded from macro 'likely'
# define likely(x) __builtin_expect(!!(x), 1)
^
include/linux/memcontrol.h:1714:2: note: Returning the value 1, which participates in a condition later
return static_branch_likely(&memcg_kmem_enabled_key);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page_alloc.c:5217:6: note: Returning from 'memcg_kmem_enabled'
if (memcg_kmem_enabled() && (gfp & __GFP_ACCOUNT))
^~~~~~~~~~~~~~~~~~~~
mm/page_alloc.c:5217:6: note: Left side of '&&' is true
mm/page_alloc.c:5217:31: note: Assuming the condition is true
if (memcg_kmem_enabled() && (gfp & __GFP_ACCOUNT))
^~~~~~~~~~~~~~~~~~~
mm/page_alloc.c:5217:2: note: Taking true branch
if (memcg_kmem_enabled() && (gfp & __GFP_ACCOUNT))
^
mm/page_alloc.c:5218:3: note: Control jumps to line 5315
goto failed;
^
mm/page_alloc.c:5316:6: note: Assuming 'page' is non-null
if (page) {
^~~~
mm/page_alloc.c:5316:2: note: Taking true branch
if (page) {
^
mm/page_alloc.c:5317:7: note: Assuming 'page_list' is null
if (page_list)
^~~~~~~~~
mm/page_alloc.c:5317:3: note: Taking false branch
if (page_list)
^
mm/page_alloc.c:5320:29: note: Array access (from variable 'page_array') results in a null pointer dereference
page_array[nr_populated] = page;
~~~~~~~~~~ ^
>> mm/page_alloc.c:5559:3: warning: Value stored to 'refcnt' is never read [clang-analyzer-deadcode.DeadStores]
refcnt = page_ref_add_return(page, PAGE_FRAG_CACHE_MAX_SIZE + 1);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page_alloc.c:5559:3: note: Value stored to 'refcnt' is never read
refcnt = page_ref_add_return(page, PAGE_FRAG_CACHE_MAX_SIZE + 1);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page_alloc.c:8380:3: warning: Division by zero [clang-analyzer-core.DivideZero]
do_div(tmp, lowmem_pages);
^
include/asm-generic/div64.h:48:26: note: expanded from macro 'do_div'
__rem = ((uint64_t)(n)) % __base; \
^
mm/page_alloc.c:8533:6: note: Assuming 'rc' is 0
if (rc)
^~
mm/page_alloc.c:8533:2: note: Taking false branch
if (rc)
^
mm/page_alloc.c:8536:6: note: Assuming 'write' is not equal to 0
if (write)
^~~~~
mm/page_alloc.c:8536:2: note: Taking true branch
if (write)
^
mm/page_alloc.c:8537:3: note: Calling 'setup_per_zone_wmarks'
setup_per_zone_wmarks();
^~~~~~~~~~~~~~~~~~~~~~~
mm/page_alloc.c:8437:2: note: Calling '__setup_per_zone_wmarks'
__setup_per_zone_wmarks();
^~~~~~~~~~~~~~~~~~~~~~~~~
mm/page_alloc.c:8365:2: note: 'lowmem_pages' initialized to 0
unsigned long lowmem_pages = 0;
^~~~~~~~~~~~~~~~~~~~~~~~~~
mm/page_alloc.c:8370:2: note: Loop condition is false. Execution continues on line 8375
for_each_zone(zone) {
^
include/linux/mmzone.h:1122:2: note: expanded from macro 'for_each_zone'
for (zone = (first_online_pgdat())->node_zones; \
^
mm/page_alloc.c:8375:2: note: Loop condition is true. Entering loop body
for_each_zone(zone) {
^
include/linux/mmzone.h:1122:2: note: expanded from macro 'for_each_zone'
for (zone = (first_online_pgdat())->node_zones; \
^
mm/page_alloc.c:8378:3: note: Loop condition is false. Exiting loop
spin_lock_irqsave(&zone->lock, flags);
^
include/linux/spinlock.h:397:2: note: expanded from macro 'spin_lock_irqsave'
raw_spin_lock_irqsave(spinlock_check(lock), flags); \
^
include/linux/spinlock.h:253:2: note: expanded from macro 'raw_spin_lock_irqsave'
do { \
^
mm/page_alloc.c:8378:3: note: Loop condition is false. Exiting loop
spin_lock_irqsave(&zone->lock, flags);
^
include/linux/spinlock.h:395:43: note: expanded from macro 'spin_lock_irqsave'
#define spin_lock_irqsave(lock, flags) \
^
mm/page_alloc.c:8380:3: note: '__base' initialized to 0
do_div(tmp, lowmem_pages);
^
include/asm-generic/div64.h:46:2: note: expanded from macro 'do_div'
uint32_t __base = (base); \
^~~~~~~~~~~~~~~
mm/page_alloc.c:8380:3: note: Division by zero
do_div(tmp, lowmem_pages);
^
include/asm-generic/div64.h:48:26: note: expanded from macro 'do_div'
__rem = ((uint64_t)(n)) % __base; \
~~~~~~~~~~~~~~~~^~~~~~~~
Suppressed 12 warnings (11 in non-user code, 1 with check filters).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
15 warnings generated.
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c:1489:2: warning: Value stored to 'r' is never read [clang-analyzer-deadcode.DeadStores]
r = amdgpu_atomfirmware_get_vram_info(adev,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/gpu/drm/amd/amdgpu/gmc_v9_0.c:1489:2: note: Value stored to 'r' is never read
r = amdgpu_atomfirmware_get_vram_info(adev,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Suppressed 14 warnings (14 in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
14 warnings generated.
Suppressed 14 warnings (14 in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
14 warnings generated.
Suppressed 14 warnings (14 in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
14 warnings generated.
Suppressed 14 warnings (14 in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
14 warnings generated.
Suppressed 14 warnings (14 in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
15 warnings generated.
drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c:852:3: warning: Value stored to 'r' is never read [clang-analyzer-deadcode.DeadStores]
r = amdgpu_atomfirmware_get_vram_info(adev,
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/gpu/drm/amd/amdgpu/gmc_v10_0.c:852:3: note: Value stored to 'r' is never read
r = amdgpu_atomfirmware_get_vram_info(adev,
vim +/refcnt +5559 mm/page_alloc.c
44fdffd70504c1 Alexander Duyck 2016-12-14 5511
b358e2122b9d7a Kevin Hao 2021-02-04 5512 void *page_frag_alloc_align(struct page_frag_cache *nc,
b358e2122b9d7a Kevin Hao 2021-02-04 5513 unsigned int fragsz, gfp_t gfp_mask,
b358e2122b9d7a Kevin Hao 2021-02-04 5514 unsigned int align_mask)
b63ae8ca096dfd Alexander Duyck 2015-05-06 5515 {
b63ae8ca096dfd Alexander Duyck 2015-05-06 5516 unsigned int size = PAGE_SIZE;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5517 struct page *page;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5518 int offset;
2add304c6e5eb6 Pasha Tatashin 2021-12-21 5519 int refcnt;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5520
b63ae8ca096dfd Alexander Duyck 2015-05-06 5521 if (unlikely(!nc->va)) {
b63ae8ca096dfd Alexander Duyck 2015-05-06 5522 refill:
2976db8018532b Alexander Duyck 2017-01-10 5523 page = __page_frag_cache_refill(nc, gfp_mask);
b63ae8ca096dfd Alexander Duyck 2015-05-06 5524 if (!page)
b63ae8ca096dfd Alexander Duyck 2015-05-06 5525 return NULL;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5526
b63ae8ca096dfd Alexander Duyck 2015-05-06 5527 #if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
b63ae8ca096dfd Alexander Duyck 2015-05-06 5528 /* if size can vary use size else just use PAGE_SIZE */
b63ae8ca096dfd Alexander Duyck 2015-05-06 5529 size = nc->size;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5530 #endif
b63ae8ca096dfd Alexander Duyck 2015-05-06 5531 /* Even if we own the page, we do not use atomic_set().
b63ae8ca096dfd Alexander Duyck 2015-05-06 5532 * This would break get_page_unless_zero() users.
b63ae8ca096dfd Alexander Duyck 2015-05-06 5533 */
8644772637deb1 Alexander Duyck 2019-02-15 5534 page_ref_add(page, PAGE_FRAG_CACHE_MAX_SIZE);
b63ae8ca096dfd Alexander Duyck 2015-05-06 5535
b63ae8ca096dfd Alexander Duyck 2015-05-06 5536 /* reset page count bias and offset to start of new frag */
2f064f3485cd29 Michal Hocko 2015-08-21 5537 nc->pfmemalloc = page_is_pfmemalloc(page);
8644772637deb1 Alexander Duyck 2019-02-15 5538 nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5539 nc->offset = size;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5540 }
b63ae8ca096dfd Alexander Duyck 2015-05-06 5541
b63ae8ca096dfd Alexander Duyck 2015-05-06 5542 offset = nc->offset - fragsz;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5543 if (unlikely(offset < 0)) {
b63ae8ca096dfd Alexander Duyck 2015-05-06 5544 page = virt_to_page(nc->va);
b63ae8ca096dfd Alexander Duyck 2015-05-06 5545
fe896d1878949e Joonsoo Kim 2016-03-17 5546 if (!page_ref_sub_and_test(page, nc->pagecnt_bias))
b63ae8ca096dfd Alexander Duyck 2015-05-06 5547 goto refill;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5548
d8c19014bba8f5 Dongli Zhang 2020-11-15 5549 if (unlikely(nc->pfmemalloc)) {
d8c19014bba8f5 Dongli Zhang 2020-11-15 5550 free_the_page(page, compound_order(page));
d8c19014bba8f5 Dongli Zhang 2020-11-15 5551 goto refill;
d8c19014bba8f5 Dongli Zhang 2020-11-15 5552 }
d8c19014bba8f5 Dongli Zhang 2020-11-15 5553
b63ae8ca096dfd Alexander Duyck 2015-05-06 5554 #if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE)
b63ae8ca096dfd Alexander Duyck 2015-05-06 5555 /* if size can vary use size else just use PAGE_SIZE */
b63ae8ca096dfd Alexander Duyck 2015-05-06 5556 size = nc->size;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5557 #endif
2add304c6e5eb6 Pasha Tatashin 2021-12-21 5558 /* page count is 0, set it to PAGE_FRAG_CACHE_MAX_SIZE + 1 */
2add304c6e5eb6 Pasha Tatashin 2021-12-21 @5559 refcnt = page_ref_add_return(page, PAGE_FRAG_CACHE_MAX_SIZE + 1);
2add304c6e5eb6 Pasha Tatashin 2021-12-21 5560 VM_BUG_ON_PAGE(refcnt != PAGE_FRAG_CACHE_MAX_SIZE + 1, page);
b63ae8ca096dfd Alexander Duyck 2015-05-06 5561
b63ae8ca096dfd Alexander Duyck 2015-05-06 5562 /* reset page count bias and offset to start of new frag */
8644772637deb1 Alexander Duyck 2019-02-15 5563 nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5564 offset = size - fragsz;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5565 }
b63ae8ca096dfd Alexander Duyck 2015-05-06 5566
b63ae8ca096dfd Alexander Duyck 2015-05-06 5567 nc->pagecnt_bias--;
b358e2122b9d7a Kevin Hao 2021-02-04 5568 offset &= align_mask;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5569 nc->offset = offset;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5570
b63ae8ca096dfd Alexander Duyck 2015-05-06 5571 return nc->va + offset;
b63ae8ca096dfd Alexander Duyck 2015-05-06 5572 }
b358e2122b9d7a Kevin Hao 2021-02-04 5573 EXPORT_SYMBOL(page_frag_alloc_align);
b63ae8ca096dfd Alexander Duyck 2015-05-06 5574
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org
^ permalink raw reply [flat|nested] 2+ messages in thread* [PATCH v2 0/9] Hardening page _refcount
@ 2021-12-21 15:01 Pasha Tatashin
2021-12-21 15:01 ` [PATCH v2 3/9] mm: remove set_page_count() from page_frag_alloc_align Pasha Tatashin
0 siblings, 1 reply; 2+ messages in thread
From: Pasha Tatashin @ 2021-12-21 15:01 UTC (permalink / raw)
To: pasha.tatashin, linux-kernel, linux-mm, linux-m68k,
anshuman.khandual, willy, akpm, william.kucharski, mike.kravetz,
vbabka, geert, schmitzmic, rostedt, mingo, hannes, guro,
songmuchun, weixugc, gthelen, rientjes, pjt
From: Pasha Tatashin <tatashin@google.com>
Changelog:
v2:
- As suggested by Matthew Wilcox removed "mm: page_ref_add_unless()
does not trace 'u' argument" patch as page_ref_add_unless is going
away.
v1:
- sync with the latest linux-next
RFCv2:
- use the "fetch" variant instead of "return" of atomic instructions
- allow negative values, as we are using all 32-bits of _refcount.
It is hard to root cause _refcount problems, because they usually
manifest after the damage has occurred. Yet, they can lead to
catastrophic failures such memory corruptions. There were a number
of refcount related issues discovered recently [1], [2], [3].
Improve debugability by adding more checks that ensure that
page->_refcount never turns negative (i.e. double free does not
happen, or free after freeze etc).
- Check for overflow and underflow right from the functions that
modify _refcount
- Remove set_page_count(), so we do not unconditionally overwrite
_refcount with an unrestrained value
- Trace return values in all functions that modify _refcount
Applies against next-20211221.
Previous verions:
v1: https://lore.kernel.org/all/20211208203544.2297121-1-pasha.tatashin@soleen.com
RFCv2: https://lore.kernel.org/all/20211117012059.141450-1-pasha.tatashin@soleen.com
RFCv1: https://lore.kernel.org/all/20211026173822.502506-1-pasha.tatashin@soleen.com
[1] https://lore.kernel.org/all/xr9335nxwc5y.fsf@gthelen2.svl.corp.google.com
[2] https://lore.kernel.org/all/1582661774-30925-2-git-send-email-akaher@vmware.com
[3] https://lore.kernel.org/all/20210622021423.154662-3-mike.kravetz@oracle.com
Pasha Tatashin (9):
mm: add overflow and underflow checks for page->_refcount
mm: Avoid using set_page_count() in set_page_recounted()
mm: remove set_page_count() from page_frag_alloc_align
mm: avoid using set_page_count() when pages are freed into allocator
mm: rename init_page_count() -> page_ref_init()
mm: remove set_page_count()
mm: simplify page_ref_* functions
mm: do not use atomic_set_release in page_ref_unfreeze()
mm: use atomic_cmpxchg_acquire in page_ref_freeze().
arch/m68k/mm/motorola.c | 2 +-
include/linux/mm.h | 2 +-
include/linux/page_ref.h | 149 +++++++++++++++-----------------
include/trace/events/page_ref.h | 58 ++++++++-----
mm/debug_page_ref.c | 22 +----
mm/internal.h | 6 +-
mm/page_alloc.c | 19 ++--
7 files changed, 132 insertions(+), 126 deletions(-)
--
2.34.1.307.g9b7440fafd-goog
^ permalink raw reply [flat|nested] 2+ messages in thread
* [PATCH v2 3/9] mm: remove set_page_count() from page_frag_alloc_align
2021-12-21 15:01 [PATCH v2 0/9] Hardening page _refcount Pasha Tatashin
@ 2021-12-21 15:01 ` Pasha Tatashin
0 siblings, 0 replies; 2+ messages in thread
From: Pasha Tatashin @ 2021-12-21 15:01 UTC (permalink / raw)
To: pasha.tatashin, linux-kernel, linux-mm, linux-m68k,
anshuman.khandual, willy, akpm, william.kucharski, mike.kravetz,
vbabka, geert, schmitzmic, rostedt, mingo, hannes, guro,
songmuchun, weixugc, gthelen, rientjes, pjt
set_page_count() unconditionally resets the value of _ref_count and that
is dangerous, as it is not programmatically verified. Instead we rely on
comments like: "OK, page count is 0, we can safely set it".
Add a new refcount function: page_ref_add_return() to return the new
refcount value after adding to it. Use the return value to verify that
the _ref_count was indeed the expected one.
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
include/linux/page_ref.h | 11 +++++++++++
mm/page_alloc.c | 6 ++++--
2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/include/linux/page_ref.h b/include/linux/page_ref.h
index fe4864f7f69c..03e21ce2f1bd 100644
--- a/include/linux/page_ref.h
+++ b/include/linux/page_ref.h
@@ -115,6 +115,17 @@ static inline void init_page_count(struct page *page)
set_page_count(page, 1);
}
+static inline int page_ref_add_return(struct page *page, int nr)
+{
+ int old_val = atomic_fetch_add(nr, &page->_refcount);
+ int new_val = old_val + nr;
+
+ VM_BUG_ON_PAGE((unsigned int)new_val < (unsigned int)old_val, page);
+ if (page_ref_tracepoint_active(page_ref_mod_and_return))
+ __page_ref_mod_and_return(page, nr, new_val);
+ return new_val;
+}
+
static inline void page_ref_add(struct page *page, int nr)
{
int old_val = atomic_fetch_add(nr, &page->_refcount);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index edfd6c81af82..b5554767b9de 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -5523,6 +5523,7 @@ void *page_frag_alloc_align(struct page_frag_cache *nc,
unsigned int size = PAGE_SIZE;
struct page *page;
int offset;
+ int refcnt;
if (unlikely(!nc->va)) {
refill:
@@ -5561,8 +5562,9 @@ void *page_frag_alloc_align(struct page_frag_cache *nc,
/* if size can vary use size else just use PAGE_SIZE */
size = nc->size;
#endif
- /* OK, page count is 0, we can safely set it */
- set_page_count(page, PAGE_FRAG_CACHE_MAX_SIZE + 1);
+ /* page count is 0, set it to PAGE_FRAG_CACHE_MAX_SIZE + 1 */
+ refcnt = page_ref_add_return(page, PAGE_FRAG_CACHE_MAX_SIZE + 1);
+ VM_BUG_ON_PAGE(refcnt != PAGE_FRAG_CACHE_MAX_SIZE + 1, page);
/* reset page count bias and offset to start of new frag */
nc->pagecnt_bias = PAGE_FRAG_CACHE_MAX_SIZE + 1;
--
2.34.1.307.g9b7440fafd-goog
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2022-01-02 12:18 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-01-02 12:18 [PATCH v2 3/9] mm: remove set_page_count() from page_frag_alloc_align kernel test robot
-- strict thread matches above, loose matches on Subject: below --
2021-12-21 15:01 [PATCH v2 0/9] Hardening page _refcount Pasha Tatashin
2021-12-21 15:01 ` [PATCH v2 3/9] mm: remove set_page_count() from page_frag_alloc_align Pasha Tatashin
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.