mirror of
https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9.git
synced 2026-09-09 00:08:12 +08:00
Merge: RHEL 9 MM subsystem proactive follow up fixes
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/7543 Updating the RHEL 9 tree with mm follow up fixes to proactively prevent issues cropping up. JIRA: https://issues.redhat.com/browse/RHEL-104908 Backport of the following patches: 6db07bb8df55 kasan: use vmalloc_dump_obj() for vmalloc error reports 87bc4b5ce41a mm/damon/lru_sort: reset enabled when DAMON start failed 5abc4befc7e3 mm/damon/reclaim: reset enabled when DAMON start failed 6ddc9fb45b26 kasan: remove kasan_find_vm_area() to prevent possible deadlock 4eb5e19038c2 mm/migrate: fix do_pages_stat in compat mode ec62cdf3079b mm/hugetlb: don't crash when allocating a folio if there are no resv 3f9d1b876d09 mm/damon/sysfs-schemes: free old damon_sysfs_scheme_filter->memcg_path on write 662b5582abb3 mm: shmem: add missing shmem_unacct_size() in __shmem_file_setup() 634d7535a52f mm: pcp: increase pcp->free_count threshold to trigger free_high eca8dc5f08b4 mm: page_alloc: remove redundant READ_ONCE 2aca24130463 mm/gup: fix wrongly calculated returned value in fault_in_safe_writeable() 8bea129b6965 kernel/fork: only call untrack_pfn_clear() on VMAs duplicated for fork() c83bf8fca6e8 mm: (un)track_pfn_copy() fix + doc improvements 8510ab2669cb mm/gup: remove unnecessary check in memfd_pin_folios() 804040866398 mm: fix filemap_get_folios_contig returning batches of identical folios ee2dc58e5161 mm/memblock: repeat setting reserved region nid if array is doubled 4d83684333a2 mm/memblock: pass size instead of end to memblock_set_node() 2a0710282377 x86/mm/pat: Fix VM_PAT handling when fork() fails in copy_page_range() dd314f2d74f6 mm/hwpoison: do not send SIGBUS to processes with recovered clean pages a046fca559fa mm/damon/sysfs-schemes: avoid Wformat-security warning on damon_sysfs_access_pattern_add_range_dir() 07275590f7fe mm/mremap: correctly handle partial mremap() of VMA starting at 0 f1549cdcdbd2 mm: respect mmap hint address when aligning for THP 27d7f8024675 mm: multi-gen LRU: use {ptep,pmdp}_clear_young_notify() 092fc8165eae mm: multi-gen LRU: remove MM_LEAF_OLD and MM_NONLEAF_TOTAL stats 68e78c47542c mm: multi-gen LRU: ignore non-leaf pmd_young for force_scan=true 3c033ac7304d kmsan: remove an x86-specific #include from kmsan.h 775cd2e44130 kmsan: remove a useless assignment from kmsan_vmap_pages_range_noflush() 432d611e7ea5 mm: hugetlb_vmemmap: fix reference to nonexistent file Includes the following CVEs: CVE: CVE-2025-22090 CVE: CVE-2025-38258 CVE: CVE-2025-38510 Signed-off-by: Audra Mitchell <audra@redhat.com> Approved-by: Herton R. Krzesinski <herton@redhat.com> Approved-by: Rafael Aquini <raquini@redhat.com> Approved-by: Luiz Capitulino <luizcap@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
This commit is contained in:
+28
-24
@@ -1000,29 +1000,42 @@ static int get_pat_info(struct vm_area_struct *vma, resource_size_t *paddr,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* track_pfn_copy is called when vma that is covering the pfnmap gets
|
||||
* copied through copy_page_range().
|
||||
*
|
||||
* If the vma has a linear pfn mapping for the entire range, we get the prot
|
||||
* from pte and reserve the entire vma range with single reserve_pfn_range call.
|
||||
*/
|
||||
int track_pfn_copy(struct vm_area_struct *vma)
|
||||
int track_pfn_copy(struct vm_area_struct *dst_vma,
|
||||
struct vm_area_struct *src_vma, unsigned long *pfn)
|
||||
{
|
||||
const unsigned long vma_size = src_vma->vm_end - src_vma->vm_start;
|
||||
resource_size_t paddr;
|
||||
unsigned long vma_size = vma->vm_end - vma->vm_start;
|
||||
pgprot_t pgprot;
|
||||
int rc;
|
||||
|
||||
if (vma->vm_flags & VM_PAT) {
|
||||
if (get_pat_info(vma, &paddr, &pgprot))
|
||||
return -EINVAL;
|
||||
/* reserve the whole chunk covered by vma. */
|
||||
return reserve_pfn_range(paddr, vma_size, &pgprot, 1);
|
||||
}
|
||||
if (!(src_vma->vm_flags & VM_PAT))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Duplicate the PAT information for the dst VMA based on the src
|
||||
* VMA.
|
||||
*/
|
||||
if (get_pat_info(src_vma, &paddr, &pgprot))
|
||||
return -EINVAL;
|
||||
rc = reserve_pfn_range(paddr, vma_size, &pgprot, 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Reservation for the destination VMA succeeded. */
|
||||
vm_flags_set(dst_vma, VM_PAT);
|
||||
*pfn = PHYS_PFN(paddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void untrack_pfn_copy(struct vm_area_struct *dst_vma, unsigned long pfn)
|
||||
{
|
||||
untrack_pfn(dst_vma, pfn, dst_vma->vm_end - dst_vma->vm_start, true);
|
||||
/*
|
||||
* Reservation was freed, any copied page tables will get cleaned
|
||||
* up later, but without getting PAT involved again.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* prot is passed in as a parameter for the new mapping. If the vma has
|
||||
* a linear pfn mapping for the entire range, or no vma is provided,
|
||||
@@ -1111,15 +1124,6 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* untrack_pfn_clear is called if the following situation fits:
|
||||
*
|
||||
* 1) while mremapping a pfnmap for a new region, with the old vma after
|
||||
* its pfnmap page table has been removed. The new vma has a new pfnmap
|
||||
* to the same pfn & cache type with VM_PAT set.
|
||||
* 2) while duplicating vm area, the new vma fails to copy the pgtable from
|
||||
* old vma.
|
||||
*/
|
||||
void untrack_pfn_clear(struct vm_area_struct *vma)
|
||||
{
|
||||
vm_flags_clear(vma, VM_PAT);
|
||||
|
||||
@@ -458,9 +458,7 @@ struct lru_gen_folio {
|
||||
|
||||
enum {
|
||||
MM_LEAF_TOTAL, /* total leaf entries */
|
||||
MM_LEAF_OLD, /* old leaf entries */
|
||||
MM_LEAF_YOUNG, /* young leaf entries */
|
||||
MM_NONLEAF_TOTAL, /* total non-leaf entries */
|
||||
MM_NONLEAF_FOUND, /* non-leaf entries found in Bloom filters */
|
||||
MM_NONLEAF_ADDED, /* non-leaf entries added to Bloom filters */
|
||||
NR_MM_STATS
|
||||
@@ -500,7 +498,7 @@ struct lru_gen_mm_walk {
|
||||
};
|
||||
|
||||
void lru_gen_init_lruvec(struct lruvec *lruvec);
|
||||
void lru_gen_look_around(struct page_vma_mapped_walk *pvmw);
|
||||
bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw);
|
||||
|
||||
#ifdef CONFIG_MEMCG
|
||||
|
||||
@@ -592,8 +590,9 @@ static inline void lru_gen_init_lruvec(struct lruvec *lruvec)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
|
||||
static inline bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MEMCG
|
||||
|
||||
+25
-6
@@ -1277,14 +1277,28 @@ static inline void track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
|
||||
}
|
||||
|
||||
/*
|
||||
* track_pfn_copy is called when vma that is covering the pfnmap gets
|
||||
* copied through copy_page_range().
|
||||
* track_pfn_copy is called when a VM_PFNMAP VMA is about to get the page
|
||||
* tables copied during copy_page_range(). Will store the pfn to be
|
||||
* passed to untrack_pfn_copy() only if there is something to be untracked.
|
||||
* Callers should initialize the pfn to 0.
|
||||
*/
|
||||
static inline int track_pfn_copy(struct vm_area_struct *vma)
|
||||
static inline int track_pfn_copy(struct vm_area_struct *dst_vma,
|
||||
struct vm_area_struct *src_vma, unsigned long *pfn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* untrack_pfn_copy is called when a VM_PFNMAP VMA failed to copy during
|
||||
* copy_page_range(), but after track_pfn_copy() was already called. Can
|
||||
* be called even if track_pfn_copy() did not actually track anything:
|
||||
* handled internally.
|
||||
*/
|
||||
static inline void untrack_pfn_copy(struct vm_area_struct *dst_vma,
|
||||
unsigned long pfn)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* untrack_pfn is called while unmapping a pfnmap for a region.
|
||||
* untrack can be called for a specific region indicated by pfn and size or
|
||||
@@ -1297,8 +1311,10 @@ static inline void untrack_pfn(struct vm_area_struct *vma,
|
||||
}
|
||||
|
||||
/*
|
||||
* untrack_pfn_clear is called while mremapping a pfnmap for a new region
|
||||
* or fails to copy pgtable during duplicate vm area.
|
||||
* untrack_pfn_clear is called in the following cases on a VM_PFNMAP VMA:
|
||||
*
|
||||
* 1) During mremap() on the src VMA after the page tables were moved.
|
||||
* 2) During fork() on the dst VMA, immediately after duplicating the src VMA.
|
||||
*/
|
||||
static inline void untrack_pfn_clear(struct vm_area_struct *vma)
|
||||
{
|
||||
@@ -1309,7 +1325,10 @@ extern int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
|
||||
unsigned long size);
|
||||
extern void track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
|
||||
pfn_t pfn);
|
||||
extern int track_pfn_copy(struct vm_area_struct *vma);
|
||||
extern int track_pfn_copy(struct vm_area_struct *dst_vma,
|
||||
struct vm_area_struct *src_vma, unsigned long *pfn);
|
||||
extern void untrack_pfn_copy(struct vm_area_struct *dst_vma,
|
||||
unsigned long pfn);
|
||||
extern void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
|
||||
unsigned long size, bool mm_wr_locked);
|
||||
extern void untrack_pfn_clear(struct vm_area_struct *vma);
|
||||
|
||||
@@ -711,6 +711,11 @@ static __latent_entropy int dup_mmap(struct mm_struct *mm,
|
||||
tmp = vm_area_dup(mpnt);
|
||||
if (!tmp)
|
||||
goto fail_nomem;
|
||||
|
||||
/* track_pfn_copy() will later take care of copying internal state. */
|
||||
if (unlikely(tmp->vm_flags & VM_PFNMAP))
|
||||
untrack_pfn_clear(tmp);
|
||||
|
||||
retval = vma_dup_policy(mpnt, tmp);
|
||||
if (retval)
|
||||
goto fail_nomem_policy;
|
||||
|
||||
+4
-1
@@ -335,7 +335,7 @@ static int __init damon_lru_sort_init(void)
|
||||
int err = damon_modules_new_paddr_ctx_target(&ctx, &target);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
ctx->callback.after_wmarks_check = damon_lru_sort_after_wmarks_check;
|
||||
ctx->callback.after_aggregation = damon_lru_sort_after_aggregation;
|
||||
@@ -344,6 +344,9 @@ static int __init damon_lru_sort_init(void)
|
||||
if (enabled)
|
||||
err = damon_lru_sort_turn(true);
|
||||
|
||||
out:
|
||||
if (err && enabled)
|
||||
enabled = false;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -285,7 +285,7 @@ static int __init damon_reclaim_init(void)
|
||||
int err = damon_modules_new_paddr_ctx_target(&ctx, &target);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
goto out;
|
||||
|
||||
ctx->callback.after_wmarks_check = damon_reclaim_after_wmarks_check;
|
||||
ctx->callback.after_aggregation = damon_reclaim_after_aggregation;
|
||||
@@ -294,6 +294,9 @@ static int __init damon_reclaim_init(void)
|
||||
if (enabled)
|
||||
err = damon_reclaim_turn(true);
|
||||
|
||||
out:
|
||||
if (err && enabled)
|
||||
enabled = false;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
@@ -376,6 +376,7 @@ static ssize_t memcg_path_store(struct kobject *kobj,
|
||||
return -ENOMEM;
|
||||
|
||||
strscpy(path, buf, count + 1);
|
||||
kfree(filter->memcg_path);
|
||||
filter->memcg_path = path;
|
||||
return count;
|
||||
}
|
||||
@@ -1051,7 +1052,7 @@ static int damon_sysfs_access_pattern_add_range_dir(
|
||||
if (!range)
|
||||
return -ENOMEM;
|
||||
err = kobject_init_and_add(&range->kobj, &damon_sysfs_ul_range_ktype,
|
||||
&access_pattern->kobj, name);
|
||||
&access_pattern->kobj, "%s", name);
|
||||
if (err)
|
||||
kobject_put(&range->kobj);
|
||||
else
|
||||
|
||||
@@ -2205,6 +2205,7 @@ unsigned filemap_get_folios_contig(struct address_space *mapping,
|
||||
*start = folio->index + nr;
|
||||
goto out;
|
||||
}
|
||||
xas_advance(&xas, folio_next_index(folio) - 1);
|
||||
continue;
|
||||
put_folio:
|
||||
folio_put(folio);
|
||||
|
||||
@@ -1956,8 +1956,8 @@ size_t fault_in_safe_writeable(const char __user *uaddr, size_t size)
|
||||
} while (start != end);
|
||||
mmap_read_unlock(mm);
|
||||
|
||||
if (size > (unsigned long)uaddr - start)
|
||||
return size - ((unsigned long)uaddr - start);
|
||||
if (size > start - (unsigned long)uaddr)
|
||||
return size - (start - (unsigned long)uaddr);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fault_in_safe_writeable);
|
||||
@@ -3614,7 +3614,7 @@ long memfd_pin_folios(struct file *memfd, loff_t start, loff_t end,
|
||||
{
|
||||
unsigned int flags, nr_folios, nr_found;
|
||||
unsigned int i, pgshift = PAGE_SHIFT;
|
||||
pgoff_t start_idx, end_idx, next_idx;
|
||||
pgoff_t start_idx, end_idx;
|
||||
struct folio *folio = NULL;
|
||||
struct folio_batch fbatch;
|
||||
struct hstate *h;
|
||||
@@ -3664,19 +3664,7 @@ long memfd_pin_folios(struct file *memfd, loff_t start, loff_t end,
|
||||
folio = NULL;
|
||||
}
|
||||
|
||||
next_idx = 0;
|
||||
for (i = 0; i < nr_found; i++) {
|
||||
/*
|
||||
* As there can be multiple entries for a
|
||||
* given folio in the batch returned by
|
||||
* filemap_get_folios_contig(), the below
|
||||
* check is to ensure that we pin and return a
|
||||
* unique set of folios between start and end.
|
||||
*/
|
||||
if (next_idx &&
|
||||
next_idx != folio_index(fbatch.folios[i]))
|
||||
continue;
|
||||
|
||||
folio = page_folio(&fbatch.folios[i]->page);
|
||||
|
||||
if (try_grab_folio(folio, 1, FOLL_PIN)) {
|
||||
@@ -3689,7 +3677,6 @@ long memfd_pin_folios(struct file *memfd, loff_t start, loff_t end,
|
||||
*offset = offset_in_folio(folio, start);
|
||||
|
||||
folios[nr_folios] = folio;
|
||||
next_idx = folio_next_index(folio);
|
||||
if (++nr_folios == max_folios)
|
||||
break;
|
||||
}
|
||||
|
||||
+6
-3
@@ -2481,12 +2481,15 @@ struct folio *alloc_hugetlb_folio_reserve(struct hstate *h, int preferred_nid,
|
||||
struct folio *folio;
|
||||
|
||||
spin_lock_irq(&hugetlb_lock);
|
||||
if (!h->resv_huge_pages) {
|
||||
spin_unlock_irq(&hugetlb_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
folio = dequeue_hugetlb_folio_nodemask(h, gfp_mask, preferred_nid,
|
||||
nmask);
|
||||
if (folio) {
|
||||
VM_BUG_ON(!h->resv_huge_pages);
|
||||
if (folio)
|
||||
h->resv_huge_pages--;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&hugetlb_lock);
|
||||
return folio;
|
||||
|
||||
@@ -16,7 +16,7 @@ void hugetlb_vmemmap_optimize(const struct hstate *h, struct page *head);
|
||||
|
||||
/*
|
||||
* Reserve one vmemmap page, all vmemmap addresses are mapped to it. See
|
||||
* Documentation/vm/vmemmap_dedup.rst.
|
||||
* Documentation/mm/vmemmap_dedup.rst.
|
||||
*/
|
||||
#define HUGETLB_VMEMMAP_RESERVE_SIZE PAGE_SIZE
|
||||
|
||||
|
||||
+4
-43
@@ -357,36 +357,6 @@ static inline bool init_task_stack_addr(const void *addr)
|
||||
sizeof(init_thread_union.stack));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is invoked with report_lock (a raw_spinlock) held. A
|
||||
* PREEMPT_RT kernel cannot call find_vm_area() as it will acquire a sleeping
|
||||
* rt_spinlock.
|
||||
*
|
||||
* For !RT kernel, the PROVE_RAW_LOCK_NESTING config option will print a
|
||||
* lockdep warning for this raw_spinlock -> spinlock dependency. This config
|
||||
* option is enabled by default to ensure better test coverage to expose this
|
||||
* kind of RT kernel problem. This lockdep splat, however, can be suppressed
|
||||
* by using DEFINE_WAIT_OVERRIDE_MAP() if it serves a useful purpose and the
|
||||
* invalid PREEMPT_RT case has been taken care of.
|
||||
*/
|
||||
static inline struct vm_struct *kasan_find_vm_area(void *addr)
|
||||
{
|
||||
static DEFINE_WAIT_OVERRIDE_MAP(vmalloc_map, LD_WAIT_SLEEP);
|
||||
struct vm_struct *va;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PREEMPT_RT))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Suppress lockdep warning and fetch vmalloc area of the
|
||||
* offending address.
|
||||
*/
|
||||
lock_map_acquire_try(&vmalloc_map);
|
||||
va = find_vm_area(addr);
|
||||
lock_map_release(&vmalloc_map);
|
||||
return va;
|
||||
}
|
||||
|
||||
static void print_address_description(void *addr, u8 tag,
|
||||
struct kasan_report_info *info)
|
||||
{
|
||||
@@ -416,19 +386,10 @@ static void print_address_description(void *addr, u8 tag,
|
||||
}
|
||||
|
||||
if (is_vmalloc_addr(addr)) {
|
||||
struct vm_struct *va = kasan_find_vm_area(addr);
|
||||
|
||||
if (va) {
|
||||
pr_err("The buggy address belongs to the virtual mapping at\n"
|
||||
" [%px, %px) created by:\n"
|
||||
" %pS\n",
|
||||
va->addr, va->addr + va->size, va->caller);
|
||||
pr_err("\n");
|
||||
|
||||
page = vmalloc_to_page(addr);
|
||||
} else {
|
||||
pr_err("The buggy address %px belongs to a vmalloc virtual mapping\n", addr);
|
||||
}
|
||||
pr_err("The buggy address belongs to a");
|
||||
if (!vmalloc_dump_obj(addr))
|
||||
pr_cont(" vmalloc virtual mapping\n");
|
||||
page = vmalloc_to_page(addr);
|
||||
}
|
||||
|
||||
if (page) {
|
||||
|
||||
+4
-4
@@ -10,14 +10,14 @@
|
||||
#ifndef __MM_KMSAN_KMSAN_H
|
||||
#define __MM_KMSAN_KMSAN_H
|
||||
|
||||
#include <asm/pgtable_64_types.h>
|
||||
#include <linux/irqflags.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/pgtable.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/stackdepot.h>
|
||||
#include <linux/stacktrace.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#define KMSAN_ALLOCA_MAGIC_ORIGIN 0xabcd0100
|
||||
#define KMSAN_CHAIN_MAGIC_ORIGIN 0xabcd0200
|
||||
|
||||
@@ -243,7 +243,6 @@ int kmsan_vmap_pages_range_noflush(unsigned long start, unsigned long end,
|
||||
s_pages[i] = shadow_page_for(pages[i]);
|
||||
o_pages[i] = origin_page_for(pages[i]);
|
||||
}
|
||||
prot = __pgprot(pgprot_val(prot) | _PAGE_NX);
|
||||
prot = PAGE_KERNEL;
|
||||
|
||||
origin_start = vmalloc_meta((void *)start, KMSAN_META_ORIGIN);
|
||||
|
||||
+12
-1
@@ -2099,11 +2099,14 @@ static void __init memmap_init_reserved_pages(void)
|
||||
struct memblock_region *region;
|
||||
phys_addr_t start, end;
|
||||
int nid;
|
||||
unsigned long max_reserved;
|
||||
|
||||
/*
|
||||
* set nid on all reserved pages and also treat struct
|
||||
* pages for the NOMAP regions as PageReserved
|
||||
*/
|
||||
repeat:
|
||||
max_reserved = memblock.reserved.max;
|
||||
for_each_mem_region(region) {
|
||||
nid = memblock_get_region_node(region);
|
||||
start = region->base;
|
||||
@@ -2112,9 +2115,17 @@ static void __init memmap_init_reserved_pages(void)
|
||||
if (memblock_is_nomap(region))
|
||||
reserve_bootmem_region(start, end, nid);
|
||||
|
||||
memblock_set_node(start, end, &memblock.reserved, nid);
|
||||
memblock_set_node(start, region->size, &memblock.reserved, nid);
|
||||
}
|
||||
|
||||
/*
|
||||
* 'max' is changed means memblock.reserved has been doubled its
|
||||
* array, which may result a new reserved region before current
|
||||
* 'start'. Now we should repeat the procedure to set its node id.
|
||||
*/
|
||||
if (max_reserved != memblock.reserved.max)
|
||||
goto repeat;
|
||||
|
||||
/* initialize struct pages for the reserved regions */
|
||||
for_each_reserved_mem_region(region) {
|
||||
nid = memblock_get_region_node(region);
|
||||
|
||||
+16
-3
@@ -842,9 +842,17 @@ static int hwpoison_hugetlb_range(pte_t *ptep, unsigned long hmask,
|
||||
#define hwpoison_hugetlb_range NULL
|
||||
#endif
|
||||
|
||||
static int hwpoison_test_walk(unsigned long start, unsigned long end,
|
||||
struct mm_walk *walk)
|
||||
{
|
||||
/* We also want to consider pages mapped into VM_PFNMAP. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mm_walk_ops hwpoison_walk_ops = {
|
||||
.pmd_entry = hwpoison_pte_range,
|
||||
.hugetlb_entry = hwpoison_hugetlb_range,
|
||||
.test_walk = hwpoison_test_walk,
|
||||
.walk_lock = PGWALK_RDLOCK,
|
||||
};
|
||||
|
||||
@@ -879,12 +887,17 @@ static int kill_accessing_process(struct task_struct *p, unsigned long pfn,
|
||||
mmap_read_lock(p->mm);
|
||||
ret = walk_page_range(p->mm, 0, TASK_SIZE, &hwpoison_walk_ops,
|
||||
(void *)&priv);
|
||||
/*
|
||||
* ret = 1 when CMCI wins, regardless of whether try_to_unmap()
|
||||
* succeeds or fails, then kill the process with SIGBUS.
|
||||
* ret = 0 when poison page is a clean page and it's dropped, no
|
||||
* SIGBUS is needed.
|
||||
*/
|
||||
if (ret == 1 && priv.tk.addr)
|
||||
kill_proc(&priv.tk, pfn, flags);
|
||||
else
|
||||
ret = 0;
|
||||
mmap_read_unlock(p->mm);
|
||||
return ret > 0 ? -EHWPOISON : -EFAULT;
|
||||
|
||||
return ret > 0 ? -EHWPOISON : 0;
|
||||
}
|
||||
|
||||
static const char *action_name[] = {
|
||||
|
||||
+4
-7
@@ -1279,12 +1279,12 @@ int
|
||||
copy_page_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma)
|
||||
{
|
||||
pgd_t *src_pgd, *dst_pgd;
|
||||
unsigned long next;
|
||||
unsigned long addr = src_vma->vm_start;
|
||||
unsigned long end = src_vma->vm_end;
|
||||
struct mm_struct *dst_mm = dst_vma->vm_mm;
|
||||
struct mm_struct *src_mm = src_vma->vm_mm;
|
||||
struct mmu_notifier_range range;
|
||||
unsigned long next, pfn = 0;
|
||||
bool is_cow;
|
||||
int ret;
|
||||
|
||||
@@ -1295,11 +1295,7 @@ copy_page_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma)
|
||||
return copy_hugetlb_page_range(dst_mm, src_mm, dst_vma, src_vma);
|
||||
|
||||
if (unlikely(src_vma->vm_flags & VM_PFNMAP)) {
|
||||
/*
|
||||
* We do not free on error cases below as remove_vma
|
||||
* gets called on error from higher level routine
|
||||
*/
|
||||
ret = track_pfn_copy(src_vma);
|
||||
ret = track_pfn_copy(dst_vma, src_vma, &pfn);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -1336,7 +1332,6 @@ copy_page_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma)
|
||||
continue;
|
||||
if (unlikely(copy_p4d_range(dst_vma, src_vma, dst_pgd, src_pgd,
|
||||
addr, next))) {
|
||||
untrack_pfn_clear(dst_vma);
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
@@ -1346,6 +1341,8 @@ copy_page_range(struct vm_area_struct *dst_vma, struct vm_area_struct *src_vma)
|
||||
raw_write_seqcount_end(&src_mm->write_protect_seq);
|
||||
mmu_notifier_invalidate_range_end(&range);
|
||||
}
|
||||
if (ret && unlikely(src_vma->vm_flags & VM_PFNMAP))
|
||||
untrack_pfn_copy(dst_vma, pfn);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+8
-6
@@ -2340,6 +2340,7 @@ set_status:
|
||||
|
||||
static int get_compat_pages_array(const void __user *chunk_pages[],
|
||||
const void __user * __user *pages,
|
||||
unsigned long chunk_offset,
|
||||
unsigned long chunk_nr)
|
||||
{
|
||||
compat_uptr_t __user *pages32 = (compat_uptr_t __user *)pages;
|
||||
@@ -2347,7 +2348,7 @@ static int get_compat_pages_array(const void __user *chunk_pages[],
|
||||
int i;
|
||||
|
||||
for (i = 0; i < chunk_nr; i++) {
|
||||
if (get_user(p, pages32 + i))
|
||||
if (get_user(p, pages32 + chunk_offset + i))
|
||||
return -EFAULT;
|
||||
chunk_pages[i] = compat_ptr(p);
|
||||
}
|
||||
@@ -2366,27 +2367,28 @@ static int do_pages_stat(struct mm_struct *mm, unsigned long nr_pages,
|
||||
#define DO_PAGES_STAT_CHUNK_NR 16UL
|
||||
const void __user *chunk_pages[DO_PAGES_STAT_CHUNK_NR];
|
||||
int chunk_status[DO_PAGES_STAT_CHUNK_NR];
|
||||
unsigned long chunk_offset = 0;
|
||||
|
||||
while (nr_pages) {
|
||||
unsigned long chunk_nr = min(nr_pages, DO_PAGES_STAT_CHUNK_NR);
|
||||
|
||||
if (in_compat_syscall()) {
|
||||
if (get_compat_pages_array(chunk_pages, pages,
|
||||
chunk_nr))
|
||||
chunk_offset, chunk_nr))
|
||||
break;
|
||||
} else {
|
||||
if (copy_from_user(chunk_pages, pages,
|
||||
if (copy_from_user(chunk_pages, pages + chunk_offset,
|
||||
chunk_nr * sizeof(*chunk_pages)))
|
||||
break;
|
||||
}
|
||||
|
||||
do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status);
|
||||
|
||||
if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status)))
|
||||
if (copy_to_user(status + chunk_offset, chunk_status,
|
||||
chunk_nr * sizeof(*status)))
|
||||
break;
|
||||
|
||||
pages += chunk_nr;
|
||||
status += chunk_nr;
|
||||
chunk_offset += chunk_nr;
|
||||
nr_pages -= chunk_nr;
|
||||
}
|
||||
return nr_pages ? -EFAULT : 0;
|
||||
|
||||
@@ -1868,6 +1868,7 @@ __get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
|
||||
if (get_area) {
|
||||
addr = get_area(file, addr, len, pgoff, flags);
|
||||
} else if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && !file
|
||||
&& !addr /* no hint */
|
||||
&& IS_ALIGNED(len, PMD_SIZE)) {
|
||||
/* Ensures that larger anonymous mappings are THP aligned. */
|
||||
addr = thp_get_unmapped_area_vmflags(file, addr, len,
|
||||
|
||||
+5
-5
@@ -629,8 +629,8 @@ static unsigned long move_vma(struct vm_area_struct *vma,
|
||||
unsigned long vm_flags = vma->vm_flags;
|
||||
unsigned long new_pgoff;
|
||||
unsigned long moved_len;
|
||||
unsigned long account_start = 0;
|
||||
unsigned long account_end = 0;
|
||||
bool account_start = false;
|
||||
bool account_end = false;
|
||||
unsigned long hiwater_vm;
|
||||
int err = 0;
|
||||
bool need_rmap_locks;
|
||||
@@ -712,9 +712,9 @@ static unsigned long move_vma(struct vm_area_struct *vma,
|
||||
if (vm_flags & VM_ACCOUNT && !(flags & MREMAP_DONTUNMAP)) {
|
||||
vm_flags_clear(vma, VM_ACCOUNT);
|
||||
if (vma->vm_start < old_addr)
|
||||
account_start = vma->vm_start;
|
||||
account_start = true;
|
||||
if (vma->vm_end > old_addr + old_len)
|
||||
account_end = vma->vm_end;
|
||||
account_end = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -754,7 +754,7 @@ static unsigned long move_vma(struct vm_area_struct *vma,
|
||||
/* OOM: unable to split vma, just get accounts right */
|
||||
if (vm_flags & VM_ACCOUNT && !(flags & MREMAP_DONTUNMAP))
|
||||
vm_acct_memory(old_len >> PAGE_SHIFT);
|
||||
account_start = account_end = 0;
|
||||
account_start = account_end = false;
|
||||
}
|
||||
|
||||
if (vm_flags & VM_LOCKED) {
|
||||
|
||||
+2
-2
@@ -2476,10 +2476,10 @@ static void free_unref_page_commit(struct zone *zone, struct per_cpu_pages *pcp,
|
||||
* stops will be drained from vmstat refresh context.
|
||||
*/
|
||||
if (order && order <= PAGE_ALLOC_COSTLY_ORDER) {
|
||||
free_high = (pcp->free_count >= batch &&
|
||||
free_high = (pcp->free_count >= (batch + pcp->high_min / 2) &&
|
||||
(pcp->flags & PCPF_PREV_FREE_HIGH_ORDER) &&
|
||||
(!(pcp->flags & PCPF_FREE_HIGH_BATCH) ||
|
||||
pcp->count >= READ_ONCE(batch)));
|
||||
pcp->count >= batch));
|
||||
pcp->flags |= PCPF_PREV_FREE_HIGH_ORDER;
|
||||
} else if (pcp->flags & PCPF_PREV_FREE_HIGH_ORDER) {
|
||||
pcp->flags &= ~PCPF_PREV_FREE_HIGH_ORDER;
|
||||
|
||||
@@ -820,13 +820,11 @@ static bool folio_referenced_one(struct folio *folio,
|
||||
return false; /* To break the loop */
|
||||
}
|
||||
|
||||
if (pvmw.pte) {
|
||||
if (lru_gen_enabled() && pte_young(ptep_get(pvmw.pte)) &&
|
||||
!(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ))) {
|
||||
lru_gen_look_around(&pvmw);
|
||||
if ((lru_gen_enabled() && pvmw.pte) &&
|
||||
!(vma->vm_flags & (VM_SEQ_READ | VM_RAND_READ))) {
|
||||
if (lru_gen_look_around(&pvmw))
|
||||
referenced++;
|
||||
}
|
||||
|
||||
} else if (pvmw.pte) {
|
||||
if (ptep_clear_flush_young_notify(vma, address,
|
||||
pvmw.pte)) {
|
||||
/*
|
||||
|
||||
+3
-3
@@ -4830,12 +4830,12 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name, l
|
||||
if (size < 0 || size > MAX_LFS_FILESIZE)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (shmem_acct_size(flags, size))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
if (is_idmapped_mnt(mnt))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (shmem_acct_size(flags, size))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
inode = shmem_get_inode(&nop_mnt_idmap, mnt->mnt_sb, NULL,
|
||||
S_IFREG | S_IRWXUGO, 0, flags);
|
||||
|
||||
|
||||
+54
-47
@@ -57,6 +57,7 @@
|
||||
#include <linux/khugepaged.h>
|
||||
#include <linux/rculist_nulls.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/mmu_notifier.h>
|
||||
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/div64.h>
|
||||
@@ -3214,7 +3215,8 @@ static bool get_next_vma(unsigned long mask, unsigned long size, struct mm_walk
|
||||
return false;
|
||||
}
|
||||
|
||||
static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned long addr)
|
||||
static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned long addr,
|
||||
struct pglist_data *pgdat)
|
||||
{
|
||||
unsigned long pfn = pte_pfn(pte);
|
||||
|
||||
@@ -3226,14 +3228,21 @@ static unsigned long get_pte_pfn(pte_t pte, struct vm_area_struct *vma, unsigned
|
||||
if (WARN_ON_ONCE(pte_devmap(pte) || pte_special(pte)))
|
||||
return -1;
|
||||
|
||||
if (!pte_young(pte) && !mm_has_notifiers(vma->vm_mm))
|
||||
return -1;
|
||||
|
||||
if (WARN_ON_ONCE(!pfn_valid(pfn)))
|
||||
return -1;
|
||||
|
||||
if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat))
|
||||
return -1;
|
||||
|
||||
return pfn;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG)
|
||||
static unsigned long get_pmd_pfn(pmd_t pmd, struct vm_area_struct *vma, unsigned long addr)
|
||||
static unsigned long get_pmd_pfn(pmd_t pmd, struct vm_area_struct *vma, unsigned long addr,
|
||||
struct pglist_data *pgdat)
|
||||
{
|
||||
unsigned long pfn = pmd_pfn(pmd);
|
||||
|
||||
@@ -3245,9 +3254,15 @@ static unsigned long get_pmd_pfn(pmd_t pmd, struct vm_area_struct *vma, unsigned
|
||||
if (WARN_ON_ONCE(pmd_devmap(pmd)))
|
||||
return -1;
|
||||
|
||||
if (!pmd_young(pmd) && !mm_has_notifiers(vma->vm_mm))
|
||||
return -1;
|
||||
|
||||
if (WARN_ON_ONCE(!pfn_valid(pfn)))
|
||||
return -1;
|
||||
|
||||
if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat))
|
||||
return -1;
|
||||
|
||||
return pfn;
|
||||
}
|
||||
#endif
|
||||
@@ -3257,10 +3272,6 @@ static struct folio *get_pfn_folio(unsigned long pfn, struct mem_cgroup *memcg,
|
||||
{
|
||||
struct folio *folio;
|
||||
|
||||
/* try to avoid unnecessary memory loads */
|
||||
if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat))
|
||||
return NULL;
|
||||
|
||||
folio = pfn_folio(pfn);
|
||||
if (folio_nid(folio) != pgdat->node_id)
|
||||
return NULL;
|
||||
@@ -3315,21 +3326,16 @@ restart:
|
||||
total++;
|
||||
walk->mm_stats[MM_LEAF_TOTAL]++;
|
||||
|
||||
pfn = get_pte_pfn(ptent, args->vma, addr);
|
||||
pfn = get_pte_pfn(ptent, args->vma, addr, pgdat);
|
||||
if (pfn == -1)
|
||||
continue;
|
||||
|
||||
if (!pte_young(ptent)) {
|
||||
walk->mm_stats[MM_LEAF_OLD]++;
|
||||
continue;
|
||||
}
|
||||
|
||||
folio = get_pfn_folio(pfn, memcg, pgdat, walk->can_swap);
|
||||
if (!folio)
|
||||
continue;
|
||||
|
||||
if (!ptep_test_and_clear_young(args->vma, addr, pte + i))
|
||||
VM_WARN_ON_ONCE(true);
|
||||
if (!ptep_clear_young_notify(args->vma, addr, pte + i))
|
||||
continue;
|
||||
|
||||
young++;
|
||||
walk->mm_stats[MM_LEAF_YOUNG]++;
|
||||
@@ -3395,21 +3401,25 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long addr, struct vm_area
|
||||
/* don't round down the first address */
|
||||
addr = i ? (*first & PMD_MASK) + i * PMD_SIZE : *first;
|
||||
|
||||
pfn = get_pmd_pfn(pmd[i], vma, addr);
|
||||
if (pfn == -1)
|
||||
if (!pmd_present(pmd[i]))
|
||||
goto next;
|
||||
|
||||
if (!pmd_trans_huge(pmd[i])) {
|
||||
if (should_clear_pmd_young())
|
||||
if (!walk->force_scan && should_clear_pmd_young() &&
|
||||
!mm_has_notifiers(args->mm))
|
||||
pmdp_test_and_clear_young(vma, addr, pmd + i);
|
||||
goto next;
|
||||
}
|
||||
|
||||
pfn = get_pmd_pfn(pmd[i], vma, addr, pgdat);
|
||||
if (pfn == -1)
|
||||
goto next;
|
||||
|
||||
folio = get_pfn_folio(pfn, memcg, pgdat, walk->can_swap);
|
||||
if (!folio)
|
||||
goto next;
|
||||
|
||||
if (!pmdp_test_and_clear_young(vma, addr, pmd + i))
|
||||
if (!pmdp_clear_young_notify(vma, addr, pmd + i))
|
||||
goto next;
|
||||
|
||||
walk->mm_stats[MM_LEAF_YOUNG]++;
|
||||
@@ -3473,27 +3483,19 @@ restart:
|
||||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
if (pmd_trans_huge(val)) {
|
||||
unsigned long pfn = pmd_pfn(val);
|
||||
struct pglist_data *pgdat = lruvec_pgdat(walk->lruvec);
|
||||
unsigned long pfn = get_pmd_pfn(val, vma, addr, pgdat);
|
||||
|
||||
walk->mm_stats[MM_LEAF_TOTAL]++;
|
||||
|
||||
if (!pmd_young(val)) {
|
||||
walk->mm_stats[MM_LEAF_OLD]++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* try to avoid unnecessary memory loads */
|
||||
if (pfn < pgdat->node_start_pfn || pfn >= pgdat_end_pfn(pgdat))
|
||||
continue;
|
||||
|
||||
walk_pmd_range_locked(pud, addr, vma, args, bitmap, &first);
|
||||
if (pfn != -1)
|
||||
walk_pmd_range_locked(pud, addr, vma, args, bitmap, &first);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
walk->mm_stats[MM_NONLEAF_TOTAL]++;
|
||||
|
||||
if (should_clear_pmd_young()) {
|
||||
if (!walk->force_scan && should_clear_pmd_young() &&
|
||||
!mm_has_notifiers(args->mm)) {
|
||||
if (!pmd_young(val))
|
||||
continue;
|
||||
|
||||
@@ -3951,13 +3953,13 @@ static void lru_gen_age_node(struct pglist_data *pgdat, struct scan_control *sc)
|
||||
* the PTE table to the Bloom filter. This forms a feedback loop between the
|
||||
* eviction and the aging.
|
||||
*/
|
||||
void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
|
||||
bool lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
|
||||
{
|
||||
int i;
|
||||
unsigned long start;
|
||||
unsigned long end;
|
||||
struct lru_gen_mm_walk *walk;
|
||||
int young = 0;
|
||||
int young = 1;
|
||||
pte_t *pte = pvmw->pte;
|
||||
unsigned long addr = pvmw->address;
|
||||
struct vm_area_struct *vma = pvmw->vma;
|
||||
@@ -3972,12 +3974,15 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
|
||||
lockdep_assert_held(pvmw->ptl);
|
||||
VM_WARN_ON_ONCE_FOLIO(folio_test_lru(folio), folio);
|
||||
|
||||
if (!ptep_clear_young_notify(vma, addr, pte))
|
||||
return false;
|
||||
|
||||
if (spin_is_contended(pvmw->ptl))
|
||||
return;
|
||||
return true;
|
||||
|
||||
/* exclude special VMAs containing anon pages from COW */
|
||||
if (vma->vm_flags & VM_SPECIAL)
|
||||
return;
|
||||
return true;
|
||||
|
||||
/* avoid taking the LRU lock under the PTL when possible */
|
||||
walk = current->reclaim_state ? current->reclaim_state->mm_walk : NULL;
|
||||
@@ -3985,6 +3990,9 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
|
||||
start = max(addr & PMD_MASK, vma->vm_start);
|
||||
end = min(addr | ~PMD_MASK, vma->vm_end - 1) + 1;
|
||||
|
||||
if (end - start == PAGE_SIZE)
|
||||
return true;
|
||||
|
||||
if (end - start > MIN_LRU_BATCH * PAGE_SIZE) {
|
||||
if (addr - start < MIN_LRU_BATCH * PAGE_SIZE / 2)
|
||||
end = start + MIN_LRU_BATCH * PAGE_SIZE;
|
||||
@@ -3998,7 +4006,7 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
|
||||
|
||||
/* folio_update_gen() requires stable folio_memcg() */
|
||||
if (!mem_cgroup_trylock_pages(memcg))
|
||||
return;
|
||||
return true;
|
||||
|
||||
arch_enter_lazy_mmu_mode();
|
||||
|
||||
@@ -4008,19 +4016,16 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
|
||||
unsigned long pfn;
|
||||
pte_t ptent = ptep_get(pte + i);
|
||||
|
||||
pfn = get_pte_pfn(ptent, vma, addr);
|
||||
pfn = get_pte_pfn(ptent, vma, addr, pgdat);
|
||||
if (pfn == -1)
|
||||
continue;
|
||||
|
||||
if (!pte_young(ptent))
|
||||
continue;
|
||||
|
||||
folio = get_pfn_folio(pfn, memcg, pgdat, can_swap);
|
||||
if (!folio)
|
||||
continue;
|
||||
|
||||
if (!ptep_test_and_clear_young(vma, addr, pte + i))
|
||||
VM_WARN_ON_ONCE(true);
|
||||
if (!ptep_clear_young_notify(vma, addr, pte + i))
|
||||
continue;
|
||||
|
||||
young++;
|
||||
|
||||
@@ -4052,6 +4057,8 @@ void lru_gen_look_around(struct page_vma_mapped_walk *pvmw)
|
||||
/* feedback from rmap walkers to page table walkers */
|
||||
if (suitable_to_scan(i, young))
|
||||
update_bloom_filter(lruvec, max_seq, pvmw->pmd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@@ -5224,11 +5231,11 @@ static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec,
|
||||
for (tier = 0; tier < MAX_NR_TIERS; tier++) {
|
||||
seq_printf(m, " %10d", tier);
|
||||
for (type = 0; type < ANON_AND_FILE; type++) {
|
||||
const char *s = " ";
|
||||
const char *s = "xxx";
|
||||
unsigned long n[3] = {};
|
||||
|
||||
if (seq == max_seq) {
|
||||
s = "RT ";
|
||||
s = "RTx";
|
||||
n[0] = READ_ONCE(lrugen->avg_refaulted[type][tier]);
|
||||
n[1] = READ_ONCE(lrugen->avg_total[type][tier]);
|
||||
} else if (seq == min_seq[type] || NR_HIST_GENS > 1) {
|
||||
@@ -5247,14 +5254,14 @@ static void lru_gen_seq_show_full(struct seq_file *m, struct lruvec *lruvec,
|
||||
|
||||
seq_puts(m, " ");
|
||||
for (i = 0; i < NR_MM_STATS; i++) {
|
||||
const char *s = " ";
|
||||
const char *s = "xxxx";
|
||||
unsigned long n = 0;
|
||||
|
||||
if (seq == max_seq && NR_HIST_GENS == 1) {
|
||||
s = "LOYNFA";
|
||||
s = "TYFA";
|
||||
n = READ_ONCE(lruvec->mm_state.stats[hist][i]);
|
||||
} else if (seq != max_seq && NR_HIST_GENS > 1) {
|
||||
s = "loynfa";
|
||||
s = "tyfa";
|
||||
n = READ_ONCE(lruvec->mm_state.stats[hist][i]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user