Commit 9b62e02e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mm-hotfixes-stable-2024-05-25-09-13' of...

Merge tag 'mm-hotfixes-stable-2024-05-25-09-13' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull misc fixes from Andrew Morton:
 "16 hotfixes, 11 of which are cc:stable.

  A few nilfs2 fixes, the remainder are for MM: a couple of selftests
  fixes, various singletons fixing various issues in various parts"

* tag 'mm-hotfixes-stable-2024-05-25-09-13' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
  mm/ksm: fix possible UAF of stable_node
  mm/memory-failure: fix handling of dissolved but not taken off from buddy pages
  mm: /proc/pid/smaps_rollup: avoid skipping vma after getting mmap_lock again
  nilfs2: fix potential hang in nilfs_detach_log_writer()
  nilfs2: fix unexpected freezing of nilfs_segctor_sync()
  nilfs2: fix use-after-free of timer for log writer thread
  selftests/mm: fix build warnings on ppc64
  arm64: patching: fix handling of execmem addresses
  selftests/mm: compaction_test: fix bogus test success and reduce probability of OOM-killer invocation
  selftests/mm: compaction_test: fix incorrect write of zero to nr_hugepages
  selftests/mm: compaction_test: fix bogus test success on Aarch64
  mailmap: update email address for Satya Priya
  mm/huge_memory: don't unpoison huge_zero_folio
  kasan, fortify: properly rename memintrinsics
  lib: add version into /proc/allocinfo output
  mm/vmalloc: fix vmalloc which may return null if called with __GFP_NOFAIL
parents a0db36ed 90e82349
...@@ -572,7 +572,7 @@ Sarangdhar Joshi <spjoshi@codeaurora.org> ...@@ -572,7 +572,7 @@ Sarangdhar Joshi <spjoshi@codeaurora.org>
Sascha Hauer <s.hauer@pengutronix.de> Sascha Hauer <s.hauer@pengutronix.de>
Sahitya Tummala <quic_stummala@quicinc.com> <stummala@codeaurora.org> Sahitya Tummala <quic_stummala@quicinc.com> <stummala@codeaurora.org>
Sathishkumar Muruganandam <quic_murugana@quicinc.com> <murugana@codeaurora.org> Sathishkumar Muruganandam <quic_murugana@quicinc.com> <murugana@codeaurora.org>
Satya Priya <quic_c_skakit@quicinc.com> <skakit@codeaurora.org> Satya Priya <quic_skakitap@quicinc.com> <quic_c_skakit@quicinc.com> <skakit@codeaurora.org>
S.Çağlar Onur <caglar@pardus.org.tr> S.Çağlar Onur <caglar@pardus.org.tr>
Sayali Lokhande <quic_sayalil@quicinc.com> <sayalil@codeaurora.org> Sayali Lokhande <quic_sayalil@quicinc.com> <sayalil@codeaurora.org>
Sean Christopherson <seanjc@google.com> <sean.j.christopherson@intel.com> Sean Christopherson <seanjc@google.com> <sean.j.christopherson@intel.com>
......
...@@ -961,13 +961,14 @@ Provides information about memory allocations at all locations in the code ...@@ -961,13 +961,14 @@ Provides information about memory allocations at all locations in the code
base. Each allocation in the code is identified by its source file, line base. Each allocation in the code is identified by its source file, line
number, module (if originates from a loadable module) and the function calling number, module (if originates from a loadable module) and the function calling
the allocation. The number of bytes allocated and number of calls at each the allocation. The number of bytes allocated and number of calls at each
location are reported. location are reported. The first line indicates the version of the file, the
second line is the header listing fields in the file.
Example output. Example output.
:: ::
> sort -rn /proc/allocinfo > tail -n +3 /proc/allocinfo | sort -rn
127664128 31168 mm/page_ext.c:270 func:alloc_page_ext 127664128 31168 mm/page_ext.c:270 func:alloc_page_ext
56373248 4737 mm/slub.c:2259 func:alloc_slab_page 56373248 4737 mm/slub.c:2259 func:alloc_slab_page
14880768 3633 mm/readahead.c:247 func:page_cache_ra_unbounded 14880768 3633 mm/readahead.c:247 func:page_cache_ra_unbounded
......
...@@ -36,7 +36,7 @@ static void __kprobes *patch_map(void *addr, int fixmap) ...@@ -36,7 +36,7 @@ static void __kprobes *patch_map(void *addr, int fixmap)
if (image) if (image)
page = phys_to_page(__pa_symbol(addr)); page = phys_to_page(__pa_symbol(addr));
else if (IS_ENABLED(CONFIG_STRICT_MODULE_RWX)) else if (IS_ENABLED(CONFIG_EXECMEM))
page = vmalloc_to_page(addr); page = vmalloc_to_page(addr);
else else
return addr; return addr;
......
...@@ -2118,8 +2118,10 @@ static void nilfs_segctor_start_timer(struct nilfs_sc_info *sci) ...@@ -2118,8 +2118,10 @@ static void nilfs_segctor_start_timer(struct nilfs_sc_info *sci)
{ {
spin_lock(&sci->sc_state_lock); spin_lock(&sci->sc_state_lock);
if (!(sci->sc_state & NILFS_SEGCTOR_COMMIT)) { if (!(sci->sc_state & NILFS_SEGCTOR_COMMIT)) {
if (sci->sc_task) {
sci->sc_timer.expires = jiffies + sci->sc_interval; sci->sc_timer.expires = jiffies + sci->sc_interval;
add_timer(&sci->sc_timer); add_timer(&sci->sc_timer);
}
sci->sc_state |= NILFS_SEGCTOR_COMMIT; sci->sc_state |= NILFS_SEGCTOR_COMMIT;
} }
spin_unlock(&sci->sc_state_lock); spin_unlock(&sci->sc_state_lock);
...@@ -2166,19 +2168,36 @@ static int nilfs_segctor_sync(struct nilfs_sc_info *sci) ...@@ -2166,19 +2168,36 @@ static int nilfs_segctor_sync(struct nilfs_sc_info *sci)
struct nilfs_segctor_wait_request wait_req; struct nilfs_segctor_wait_request wait_req;
int err = 0; int err = 0;
spin_lock(&sci->sc_state_lock);
init_wait(&wait_req.wq); init_wait(&wait_req.wq);
wait_req.err = 0; wait_req.err = 0;
atomic_set(&wait_req.done, 0); atomic_set(&wait_req.done, 0);
init_waitqueue_entry(&wait_req.wq, current);
/*
* To prevent a race issue where completion notifications from the
* log writer thread are missed, increment the request sequence count
* "sc_seq_request" and insert a wait queue entry using the current
* sequence number into the "sc_wait_request" queue at the same time
* within the lock section of "sc_state_lock".
*/
spin_lock(&sci->sc_state_lock);
wait_req.seq = ++sci->sc_seq_request; wait_req.seq = ++sci->sc_seq_request;
add_wait_queue(&sci->sc_wait_request, &wait_req.wq);
spin_unlock(&sci->sc_state_lock); spin_unlock(&sci->sc_state_lock);
init_waitqueue_entry(&wait_req.wq, current);
add_wait_queue(&sci->sc_wait_request, &wait_req.wq);
set_current_state(TASK_INTERRUPTIBLE);
wake_up(&sci->sc_wait_daemon); wake_up(&sci->sc_wait_daemon);
for (;;) { for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
/*
* Synchronize only while the log writer thread is alive.
* Leave flushing out after the log writer thread exits to
* the cleanup work in nilfs_segctor_destroy().
*/
if (!sci->sc_task)
break;
if (atomic_read(&wait_req.done)) { if (atomic_read(&wait_req.done)) {
err = wait_req.err; err = wait_req.err;
break; break;
...@@ -2194,7 +2213,7 @@ static int nilfs_segctor_sync(struct nilfs_sc_info *sci) ...@@ -2194,7 +2213,7 @@ static int nilfs_segctor_sync(struct nilfs_sc_info *sci)
return err; return err;
} }
static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err) static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err, bool force)
{ {
struct nilfs_segctor_wait_request *wrq, *n; struct nilfs_segctor_wait_request *wrq, *n;
unsigned long flags; unsigned long flags;
...@@ -2202,7 +2221,7 @@ static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err) ...@@ -2202,7 +2221,7 @@ static void nilfs_segctor_wakeup(struct nilfs_sc_info *sci, int err)
spin_lock_irqsave(&sci->sc_wait_request.lock, flags); spin_lock_irqsave(&sci->sc_wait_request.lock, flags);
list_for_each_entry_safe(wrq, n, &sci->sc_wait_request.head, wq.entry) { list_for_each_entry_safe(wrq, n, &sci->sc_wait_request.head, wq.entry) {
if (!atomic_read(&wrq->done) && if (!atomic_read(&wrq->done) &&
nilfs_cnt32_ge(sci->sc_seq_done, wrq->seq)) { (force || nilfs_cnt32_ge(sci->sc_seq_done, wrq->seq))) {
wrq->err = err; wrq->err = err;
atomic_set(&wrq->done, 1); atomic_set(&wrq->done, 1);
} }
...@@ -2320,9 +2339,20 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode, ...@@ -2320,9 +2339,20 @@ int nilfs_construct_dsync_segment(struct super_block *sb, struct inode *inode,
*/ */
static void nilfs_segctor_accept(struct nilfs_sc_info *sci) static void nilfs_segctor_accept(struct nilfs_sc_info *sci)
{ {
bool thread_is_alive;
spin_lock(&sci->sc_state_lock); spin_lock(&sci->sc_state_lock);
sci->sc_seq_accepted = sci->sc_seq_request; sci->sc_seq_accepted = sci->sc_seq_request;
thread_is_alive = (bool)sci->sc_task;
spin_unlock(&sci->sc_state_lock); spin_unlock(&sci->sc_state_lock);
/*
* This function does not race with the log writer thread's
* termination. Therefore, deleting sc_timer, which should not be
* done after the log writer thread exits, can be done safely outside
* the area protected by sc_state_lock.
*/
if (thread_is_alive)
del_timer_sync(&sci->sc_timer); del_timer_sync(&sci->sc_timer);
} }
...@@ -2340,7 +2370,7 @@ static void nilfs_segctor_notify(struct nilfs_sc_info *sci, int mode, int err) ...@@ -2340,7 +2370,7 @@ static void nilfs_segctor_notify(struct nilfs_sc_info *sci, int mode, int err)
if (mode == SC_LSEG_SR) { if (mode == SC_LSEG_SR) {
sci->sc_state &= ~NILFS_SEGCTOR_COMMIT; sci->sc_state &= ~NILFS_SEGCTOR_COMMIT;
sci->sc_seq_done = sci->sc_seq_accepted; sci->sc_seq_done = sci->sc_seq_accepted;
nilfs_segctor_wakeup(sci, err); nilfs_segctor_wakeup(sci, err, false);
sci->sc_flush_request = 0; sci->sc_flush_request = 0;
} else { } else {
if (mode == SC_FLUSH_FILE) if (mode == SC_FLUSH_FILE)
...@@ -2349,7 +2379,7 @@ static void nilfs_segctor_notify(struct nilfs_sc_info *sci, int mode, int err) ...@@ -2349,7 +2379,7 @@ static void nilfs_segctor_notify(struct nilfs_sc_info *sci, int mode, int err)
sci->sc_flush_request &= ~FLUSH_DAT_BIT; sci->sc_flush_request &= ~FLUSH_DAT_BIT;
/* re-enable timer if checkpoint creation was not done */ /* re-enable timer if checkpoint creation was not done */
if ((sci->sc_state & NILFS_SEGCTOR_COMMIT) && if ((sci->sc_state & NILFS_SEGCTOR_COMMIT) && sci->sc_task &&
time_before(jiffies, sci->sc_timer.expires)) time_before(jiffies, sci->sc_timer.expires))
add_timer(&sci->sc_timer); add_timer(&sci->sc_timer);
} }
...@@ -2539,6 +2569,7 @@ static int nilfs_segctor_thread(void *arg) ...@@ -2539,6 +2569,7 @@ static int nilfs_segctor_thread(void *arg)
int timeout = 0; int timeout = 0;
sci->sc_timer_task = current; sci->sc_timer_task = current;
timer_setup(&sci->sc_timer, nilfs_construction_timeout, 0);
/* start sync. */ /* start sync. */
sci->sc_task = current; sci->sc_task = current;
...@@ -2606,6 +2637,7 @@ static int nilfs_segctor_thread(void *arg) ...@@ -2606,6 +2637,7 @@ static int nilfs_segctor_thread(void *arg)
end_thread: end_thread:
/* end sync. */ /* end sync. */
sci->sc_task = NULL; sci->sc_task = NULL;
timer_shutdown_sync(&sci->sc_timer);
wake_up(&sci->sc_wait_task); /* for nilfs_segctor_kill_thread() */ wake_up(&sci->sc_wait_task); /* for nilfs_segctor_kill_thread() */
spin_unlock(&sci->sc_state_lock); spin_unlock(&sci->sc_state_lock);
return 0; return 0;
...@@ -2669,7 +2701,6 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct super_block *sb, ...@@ -2669,7 +2701,6 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct super_block *sb,
INIT_LIST_HEAD(&sci->sc_gc_inodes); INIT_LIST_HEAD(&sci->sc_gc_inodes);
INIT_LIST_HEAD(&sci->sc_iput_queue); INIT_LIST_HEAD(&sci->sc_iput_queue);
INIT_WORK(&sci->sc_iput_work, nilfs_iput_work_func); INIT_WORK(&sci->sc_iput_work, nilfs_iput_work_func);
timer_setup(&sci->sc_timer, nilfs_construction_timeout, 0);
sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT; sci->sc_interval = HZ * NILFS_SC_DEFAULT_TIMEOUT;
sci->sc_mjcp_freq = HZ * NILFS_SC_DEFAULT_SR_FREQ; sci->sc_mjcp_freq = HZ * NILFS_SC_DEFAULT_SR_FREQ;
...@@ -2723,6 +2754,13 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) ...@@ -2723,6 +2754,13 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci)
|| sci->sc_seq_request != sci->sc_seq_done); || sci->sc_seq_request != sci->sc_seq_done);
spin_unlock(&sci->sc_state_lock); spin_unlock(&sci->sc_state_lock);
/*
* Forcibly wake up tasks waiting in nilfs_segctor_sync(), which can
* be called from delayed iput() via nilfs_evict_inode() and can race
* with the above log writer thread termination.
*/
nilfs_segctor_wakeup(sci, 0, true);
if (flush_work(&sci->sc_iput_work)) if (flush_work(&sci->sc_iput_work))
flag = true; flag = true;
...@@ -2748,7 +2786,6 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) ...@@ -2748,7 +2786,6 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci)
down_write(&nilfs->ns_segctor_sem); down_write(&nilfs->ns_segctor_sem);
timer_shutdown_sync(&sci->sc_timer);
kfree(sci); kfree(sci);
} }
......
...@@ -970,12 +970,17 @@ static int show_smaps_rollup(struct seq_file *m, void *v) ...@@ -970,12 +970,17 @@ static int show_smaps_rollup(struct seq_file *m, void *v)
break; break;
/* Case 1 and 2 above */ /* Case 1 and 2 above */
if (vma->vm_start >= last_vma_end) if (vma->vm_start >= last_vma_end) {
smap_gather_stats(vma, &mss, 0);
last_vma_end = vma->vm_end;
continue; continue;
}
/* Case 4 above */ /* Case 4 above */
if (vma->vm_end > last_vma_end) if (vma->vm_end > last_vma_end) {
smap_gather_stats(vma, &mss, last_vma_end); smap_gather_stats(vma, &mss, last_vma_end);
last_vma_end = vma->vm_end;
}
} }
} for_each_vma(vmi, vma); } for_each_vma(vmi, vma);
......
...@@ -75,17 +75,30 @@ void __write_overflow_field(size_t avail, size_t wanted) __compiletime_warning(" ...@@ -75,17 +75,30 @@ void __write_overflow_field(size_t avail, size_t wanted) __compiletime_warning("
__ret; \ __ret; \
}) })
#if defined(CONFIG_KASAN_GENERIC) || defined(CONFIG_KASAN_SW_TAGS) #if defined(__SANITIZE_ADDRESS__)
#if !defined(CONFIG_CC_HAS_KASAN_MEMINTRINSIC_PREFIX) && !defined(CONFIG_GENERIC_ENTRY)
extern void *__underlying_memset(void *p, int c, __kernel_size_t size) __RENAME(memset);
extern void *__underlying_memmove(void *p, const void *q, __kernel_size_t size) __RENAME(memmove);
extern void *__underlying_memcpy(void *p, const void *q, __kernel_size_t size) __RENAME(memcpy);
#elif defined(CONFIG_KASAN_GENERIC)
extern void *__underlying_memset(void *p, int c, __kernel_size_t size) __RENAME(__asan_memset);
extern void *__underlying_memmove(void *p, const void *q, __kernel_size_t size) __RENAME(__asan_memmove);
extern void *__underlying_memcpy(void *p, const void *q, __kernel_size_t size) __RENAME(__asan_memcpy);
#else /* CONFIG_KASAN_SW_TAGS */
extern void *__underlying_memset(void *p, int c, __kernel_size_t size) __RENAME(__hwasan_memset);
extern void *__underlying_memmove(void *p, const void *q, __kernel_size_t size) __RENAME(__hwasan_memmove);
extern void *__underlying_memcpy(void *p, const void *q, __kernel_size_t size) __RENAME(__hwasan_memcpy);
#endif
extern void *__underlying_memchr(const void *p, int c, __kernel_size_t size) __RENAME(memchr); extern void *__underlying_memchr(const void *p, int c, __kernel_size_t size) __RENAME(memchr);
extern int __underlying_memcmp(const void *p, const void *q, __kernel_size_t size) __RENAME(memcmp); extern int __underlying_memcmp(const void *p, const void *q, __kernel_size_t size) __RENAME(memcmp);
extern void *__underlying_memcpy(void *p, const void *q, __kernel_size_t size) __RENAME(memcpy);
extern void *__underlying_memmove(void *p, const void *q, __kernel_size_t size) __RENAME(memmove);
extern void *__underlying_memset(void *p, int c, __kernel_size_t size) __RENAME(memset);
extern char *__underlying_strcat(char *p, const char *q) __RENAME(strcat); extern char *__underlying_strcat(char *p, const char *q) __RENAME(strcat);
extern char *__underlying_strcpy(char *p, const char *q) __RENAME(strcpy); extern char *__underlying_strcpy(char *p, const char *q) __RENAME(strcpy);
extern __kernel_size_t __underlying_strlen(const char *p) __RENAME(strlen); extern __kernel_size_t __underlying_strlen(const char *p) __RENAME(strlen);
extern char *__underlying_strncat(char *p, const char *q, __kernel_size_t count) __RENAME(strncat); extern char *__underlying_strncat(char *p, const char *q, __kernel_size_t count) __RENAME(strncat);
extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) __RENAME(strncpy); extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) __RENAME(strncpy);
#else #else
#if defined(__SANITIZE_MEMORY__) #if defined(__SANITIZE_MEMORY__)
...@@ -110,6 +123,7 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size) ...@@ -110,6 +123,7 @@ extern char *__underlying_strncpy(char *p, const char *q, __kernel_size_t size)
#define __underlying_strlen __builtin_strlen #define __underlying_strlen __builtin_strlen
#define __underlying_strncat __builtin_strncat #define __underlying_strncat __builtin_strncat
#define __underlying_strncpy __builtin_strncpy #define __underlying_strncpy __builtin_strncpy
#endif #endif
/** /**
......
...@@ -16,47 +16,60 @@ EXPORT_SYMBOL(_shared_alloc_tag); ...@@ -16,47 +16,60 @@ EXPORT_SYMBOL(_shared_alloc_tag);
DEFINE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT, DEFINE_STATIC_KEY_MAYBE(CONFIG_MEM_ALLOC_PROFILING_ENABLED_BY_DEFAULT,
mem_alloc_profiling_key); mem_alloc_profiling_key);
struct allocinfo_private {
struct codetag_iterator iter;
bool print_header;
};
static void *allocinfo_start(struct seq_file *m, loff_t *pos) static void *allocinfo_start(struct seq_file *m, loff_t *pos)
{ {
struct codetag_iterator *iter; struct allocinfo_private *priv;
struct codetag *ct; struct codetag *ct;
loff_t node = *pos; loff_t node = *pos;
iter = kzalloc(sizeof(*iter), GFP_KERNEL); priv = kzalloc(sizeof(*priv), GFP_KERNEL);
m->private = iter; m->private = priv;
if (!iter) if (!priv)
return NULL; return NULL;
priv->print_header = (node == 0);
codetag_lock_module_list(alloc_tag_cttype, true); codetag_lock_module_list(alloc_tag_cttype, true);
*iter = codetag_get_ct_iter(alloc_tag_cttype); priv->iter = codetag_get_ct_iter(alloc_tag_cttype);
while ((ct = codetag_next_ct(iter)) != NULL && node) while ((ct = codetag_next_ct(&priv->iter)) != NULL && node)
node--; node--;
return ct ? iter : NULL; return ct ? priv : NULL;
} }
static void *allocinfo_next(struct seq_file *m, void *arg, loff_t *pos) static void *allocinfo_next(struct seq_file *m, void *arg, loff_t *pos)
{ {
struct codetag_iterator *iter = (struct codetag_iterator *)arg; struct allocinfo_private *priv = (struct allocinfo_private *)arg;
struct codetag *ct = codetag_next_ct(iter); struct codetag *ct = codetag_next_ct(&priv->iter);
(*pos)++; (*pos)++;
if (!ct) if (!ct)
return NULL; return NULL;
return iter; return priv;
} }
static void allocinfo_stop(struct seq_file *m, void *arg) static void allocinfo_stop(struct seq_file *m, void *arg)
{ {
struct codetag_iterator *iter = (struct codetag_iterator *)m->private; struct allocinfo_private *priv = (struct allocinfo_private *)m->private;
if (iter) { if (priv) {
codetag_lock_module_list(alloc_tag_cttype, false); codetag_lock_module_list(alloc_tag_cttype, false);
kfree(iter); kfree(priv);
} }
} }
static void print_allocinfo_header(struct seq_buf *buf)
{
/* Output format version, so we can change it. */
seq_buf_printf(buf, "allocinfo - version: 1.0\n");
seq_buf_printf(buf, "# <size> <calls> <tag info>\n");
}
static void alloc_tag_to_text(struct seq_buf *out, struct codetag *ct) static void alloc_tag_to_text(struct seq_buf *out, struct codetag *ct)
{ {
struct alloc_tag *tag = ct_to_alloc_tag(ct); struct alloc_tag *tag = ct_to_alloc_tag(ct);
...@@ -71,13 +84,17 @@ static void alloc_tag_to_text(struct seq_buf *out, struct codetag *ct) ...@@ -71,13 +84,17 @@ static void alloc_tag_to_text(struct seq_buf *out, struct codetag *ct)
static int allocinfo_show(struct seq_file *m, void *arg) static int allocinfo_show(struct seq_file *m, void *arg)
{ {
struct codetag_iterator *iter = (struct codetag_iterator *)arg; struct allocinfo_private *priv = (struct allocinfo_private *)arg;
char *bufp; char *bufp;
size_t n = seq_get_buf(m, &bufp); size_t n = seq_get_buf(m, &bufp);
struct seq_buf buf; struct seq_buf buf;
seq_buf_init(&buf, bufp, n); seq_buf_init(&buf, bufp, n);
alloc_tag_to_text(&buf, iter->ct); if (priv->print_header) {
print_allocinfo_header(&buf);
priv->print_header = false;
}
alloc_tag_to_text(&buf, priv->iter.ct);
seq_commit(m, seq_buf_used(&buf)); seq_commit(m, seq_buf_used(&buf));
return 0; return 0;
} }
......
...@@ -2153,7 +2153,6 @@ static struct ksm_stable_node *stable_tree_insert(struct folio *kfolio) ...@@ -2153,7 +2153,6 @@ static struct ksm_stable_node *stable_tree_insert(struct folio *kfolio)
INIT_HLIST_HEAD(&stable_node_dup->hlist); INIT_HLIST_HEAD(&stable_node_dup->hlist);
stable_node_dup->kpfn = kpfn; stable_node_dup->kpfn = kpfn;
folio_set_stable_node(kfolio, stable_node_dup);
stable_node_dup->rmap_hlist_len = 0; stable_node_dup->rmap_hlist_len = 0;
DO_NUMA(stable_node_dup->nid = nid); DO_NUMA(stable_node_dup->nid = nid);
if (!need_chain) { if (!need_chain) {
...@@ -2172,6 +2171,8 @@ static struct ksm_stable_node *stable_tree_insert(struct folio *kfolio) ...@@ -2172,6 +2171,8 @@ static struct ksm_stable_node *stable_tree_insert(struct folio *kfolio)
stable_node_chain_add_dup(stable_node_dup, stable_node); stable_node_chain_add_dup(stable_node_dup, stable_node);
} }
folio_set_stable_node(kfolio, stable_node_dup);
return stable_node_dup; return stable_node_dup;
} }
......
...@@ -1221,7 +1221,7 @@ static int me_huge_page(struct page_state *ps, struct page *p) ...@@ -1221,7 +1221,7 @@ static int me_huge_page(struct page_state *ps, struct page *p)
* subpages. * subpages.
*/ */
folio_put(folio); folio_put(folio);
if (__page_handle_poison(p) >= 0) { if (__page_handle_poison(p) > 0) {
page_ref_inc(p); page_ref_inc(p);
res = MF_RECOVERED; res = MF_RECOVERED;
} else { } else {
...@@ -2091,7 +2091,7 @@ static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb ...@@ -2091,7 +2091,7 @@ static int try_memory_failure_hugetlb(unsigned long pfn, int flags, int *hugetlb
*/ */
if (res == 0) { if (res == 0) {
folio_unlock(folio); folio_unlock(folio);
if (__page_handle_poison(p) >= 0) { if (__page_handle_poison(p) > 0) {
page_ref_inc(p); page_ref_inc(p);
res = MF_RECOVERED; res = MF_RECOVERED;
} else { } else {
...@@ -2546,6 +2546,13 @@ int unpoison_memory(unsigned long pfn) ...@@ -2546,6 +2546,13 @@ int unpoison_memory(unsigned long pfn)
goto unlock_mutex; goto unlock_mutex;
} }
if (is_huge_zero_folio(folio)) {
unpoison_pr_info("Unpoison: huge zero page is not supported %#lx\n",
pfn, &unpoison_rs);
ret = -EOPNOTSUPP;
goto unlock_mutex;
}
if (!PageHWPoison(p)) { if (!PageHWPoison(p)) {
unpoison_pr_info("Unpoison: Page was already unpoisoned %#lx\n", unpoison_pr_info("Unpoison: Page was already unpoisoned %#lx\n",
pfn, &unpoison_rs); pfn, &unpoison_rs);
......
...@@ -3498,7 +3498,7 @@ vm_area_alloc_pages(gfp_t gfp, int nid, ...@@ -3498,7 +3498,7 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
{ {
unsigned int nr_allocated = 0; unsigned int nr_allocated = 0;
gfp_t alloc_gfp = gfp; gfp_t alloc_gfp = gfp;
bool nofail = false; bool nofail = gfp & __GFP_NOFAIL;
struct page *page; struct page *page;
int i; int i;
...@@ -3555,12 +3555,11 @@ vm_area_alloc_pages(gfp_t gfp, int nid, ...@@ -3555,12 +3555,11 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
* and compaction etc. * and compaction etc.
*/ */
alloc_gfp &= ~__GFP_NOFAIL; alloc_gfp &= ~__GFP_NOFAIL;
nofail = true;
} }
/* High-order pages or fallback path if "bulk" fails. */ /* High-order pages or fallback path if "bulk" fails. */
while (nr_allocated < nr_pages) { while (nr_allocated < nr_pages) {
if (fatal_signal_pending(current)) if (!nofail && fatal_signal_pending(current))
break; break;
if (nid == NUMA_NO_NODE) if (nid == NUMA_NO_NODE)
......
...@@ -82,12 +82,16 @@ int prereq(void) ...@@ -82,12 +82,16 @@ int prereq(void)
return -1; return -1;
} }
int check_compaction(unsigned long mem_free, unsigned int hugepage_size) int check_compaction(unsigned long mem_free, unsigned long hugepage_size,
unsigned long initial_nr_hugepages)
{ {
unsigned long nr_hugepages_ul;
int fd, ret = -1; int fd, ret = -1;
int compaction_index = 0; int compaction_index = 0;
char initial_nr_hugepages[10] = {0}; char nr_hugepages[20] = {0};
char nr_hugepages[10] = {0}; char init_nr_hugepages[20] = {0};
sprintf(init_nr_hugepages, "%lu", initial_nr_hugepages);
/* We want to test with 80% of available memory. Else, OOM killer comes /* We want to test with 80% of available memory. Else, OOM killer comes
in to play */ in to play */
...@@ -101,21 +105,6 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) ...@@ -101,21 +105,6 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size)
goto out; goto out;
} }
if (read(fd, initial_nr_hugepages, sizeof(initial_nr_hugepages)) <= 0) {
ksft_print_msg("Failed to read from /proc/sys/vm/nr_hugepages: %s\n",
strerror(errno));
goto close_fd;
}
/* Start with the initial condition of 0 huge pages*/
if (write(fd, "0", sizeof(char)) != sizeof(char)) {
ksft_print_msg("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n",
strerror(errno));
goto close_fd;
}
lseek(fd, 0, SEEK_SET);
/* Request a large number of huge pages. The Kernel will allocate /* Request a large number of huge pages. The Kernel will allocate
as much as it can */ as much as it can */
if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) { if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) {
...@@ -134,22 +123,27 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) ...@@ -134,22 +123,27 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size)
/* We should have been able to request at least 1/3 rd of the memory in /* We should have been able to request at least 1/3 rd of the memory in
huge pages */ huge pages */
compaction_index = mem_free/(atoi(nr_hugepages) * hugepage_size); nr_hugepages_ul = strtoul(nr_hugepages, NULL, 10);
if (!nr_hugepages_ul) {
ksft_print_msg("ERROR: No memory is available as huge pages\n");
goto close_fd;
}
compaction_index = mem_free/(nr_hugepages_ul * hugepage_size);
lseek(fd, 0, SEEK_SET); lseek(fd, 0, SEEK_SET);
if (write(fd, initial_nr_hugepages, strlen(initial_nr_hugepages)) if (write(fd, init_nr_hugepages, strlen(init_nr_hugepages))
!= strlen(initial_nr_hugepages)) { != strlen(init_nr_hugepages)) {
ksft_print_msg("Failed to write value to /proc/sys/vm/nr_hugepages: %s\n", ksft_print_msg("Failed to write value to /proc/sys/vm/nr_hugepages: %s\n",
strerror(errno)); strerror(errno));
goto close_fd; goto close_fd;
} }
ksft_print_msg("Number of huge pages allocated = %d\n", ksft_print_msg("Number of huge pages allocated = %lu\n",
atoi(nr_hugepages)); nr_hugepages_ul);
if (compaction_index > 3) { if (compaction_index > 3) {
ksft_print_msg("ERROR: Less that 1/%d of memory is available\n" ksft_print_msg("ERROR: Less than 1/%d of memory is available\n"
"as huge pages\n", compaction_index); "as huge pages\n", compaction_index);
goto close_fd; goto close_fd;
} }
...@@ -163,6 +157,41 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size) ...@@ -163,6 +157,41 @@ int check_compaction(unsigned long mem_free, unsigned int hugepage_size)
return ret; return ret;
} }
int set_zero_hugepages(unsigned long *initial_nr_hugepages)
{
int fd, ret = -1;
char nr_hugepages[20] = {0};
fd = open("/proc/sys/vm/nr_hugepages", O_RDWR | O_NONBLOCK);
if (fd < 0) {
ksft_print_msg("Failed to open /proc/sys/vm/nr_hugepages: %s\n",
strerror(errno));
goto out;
}
if (read(fd, nr_hugepages, sizeof(nr_hugepages)) <= 0) {
ksft_print_msg("Failed to read from /proc/sys/vm/nr_hugepages: %s\n",
strerror(errno));
goto close_fd;
}
lseek(fd, 0, SEEK_SET);
/* Start with the initial condition of 0 huge pages */
if (write(fd, "0", sizeof(char)) != sizeof(char)) {
ksft_print_msg("Failed to write 0 to /proc/sys/vm/nr_hugepages: %s\n",
strerror(errno));
goto close_fd;
}
*initial_nr_hugepages = strtoul(nr_hugepages, NULL, 10);
ret = 0;
close_fd:
close(fd);
out:
return ret;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
...@@ -173,6 +202,7 @@ int main(int argc, char **argv) ...@@ -173,6 +202,7 @@ int main(int argc, char **argv)
unsigned long mem_free = 0; unsigned long mem_free = 0;
unsigned long hugepage_size = 0; unsigned long hugepage_size = 0;
long mem_fragmentable_MB = 0; long mem_fragmentable_MB = 0;
unsigned long initial_nr_hugepages;
ksft_print_header(); ksft_print_header();
...@@ -181,6 +211,10 @@ int main(int argc, char **argv) ...@@ -181,6 +211,10 @@ int main(int argc, char **argv)
ksft_set_plan(1); ksft_set_plan(1);
/* Start the test without hugepages reducing mem_free */
if (set_zero_hugepages(&initial_nr_hugepages))
ksft_exit_fail();
lim.rlim_cur = RLIM_INFINITY; lim.rlim_cur = RLIM_INFINITY;
lim.rlim_max = RLIM_INFINITY; lim.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_MEMLOCK, &lim)) if (setrlimit(RLIMIT_MEMLOCK, &lim))
...@@ -224,7 +258,8 @@ int main(int argc, char **argv) ...@@ -224,7 +258,8 @@ int main(int argc, char **argv)
entry = entry->next; entry = entry->next;
} }
if (check_compaction(mem_free, hugepage_size) == 0) if (check_compaction(mem_free, hugepage_size,
initial_nr_hugepages) == 0)
ksft_exit_pass(); ksft_exit_pass();
ksft_exit_fail(); ksft_exit_fail();
......
#define __SANE_USERSPACE_TYPES__ // Use ll64
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define __UFFD_COMMON_H__ #define __UFFD_COMMON_H__
#define _GNU_SOURCE #define _GNU_SOURCE
#define __SANE_USERSPACE_TYPES__ // Use ll64
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment