summaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
Diffstat (limited to 'mm')
-rw-r--r--mm/damon/lru_sort.c85
-rw-r--r--mm/damon/reclaim.c85
-rw-r--r--mm/damon/stat.c30
-rw-r--r--mm/damon/sysfs-schemes.c24
-rw-r--r--mm/hugetlb_cma.c1
-rw-r--r--mm/memcontrol.c29
-rw-r--r--mm/page-writeback.c16
-rw-r--r--mm/page_alloc.c5
-rw-r--r--mm/slub.c4
-rw-r--r--mm/userfaultfd.c12
-rw-r--r--mm/util.c26
-rw-r--r--mm/vma.c3
-rw-r--r--mm/vmalloc.c2
13 files changed, 218 insertions, 104 deletions
diff --git a/mm/damon/lru_sort.c b/mm/damon/lru_sort.c
index 554559d72976..8494040b1ee4 100644
--- a/mm/damon/lru_sort.c
+++ b/mm/damon/lru_sort.c
@@ -161,15 +161,6 @@ module_param(monitor_region_end, ulong, 0600);
*/
static unsigned long addr_unit __read_mostly = 1;
-/*
- * PID of the DAMON thread
- *
- * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread.
- * Else, -1.
- */
-static int kdamond_pid __read_mostly = -1;
-module_param(kdamond_pid, int, 0400);
-
static struct damos_stat damon_lru_sort_hot_stat;
DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_lru_sort_hot_stat,
lru_sort_tried_hot_regions, lru_sorted_hot_regions,
@@ -386,12 +377,8 @@ static int damon_lru_sort_turn(bool on)
{
int err;
- if (!on) {
- err = damon_stop(&ctx, 1);
- if (!err)
- kdamond_pid = -1;
- return err;
- }
+ if (!on)
+ return damon_stop(&ctx, 1);
err = damon_lru_sort_apply_parameters();
if (err)
@@ -400,9 +387,6 @@ static int damon_lru_sort_turn(bool on)
err = damon_start(&ctx, 1, true);
if (err)
return err;
- kdamond_pid = damon_kdamond_pid(ctx);
- if (kdamond_pid < 0)
- return kdamond_pid;
return damon_call(ctx, &call_control);
}
@@ -430,42 +414,83 @@ module_param_cb(addr_unit, &addr_unit_param_ops, &addr_unit, 0600);
MODULE_PARM_DESC(addr_unit,
"Scale factor for DAMON_LRU_SORT to ops address conversion (default: 1)");
+static bool damon_lru_sort_enabled(void)
+{
+ if (!ctx)
+ return false;
+ return damon_is_running(ctx);
+}
+
static int damon_lru_sort_enabled_store(const char *val,
const struct kernel_param *kp)
{
- bool is_enabled = enabled;
- bool enable;
int err;
- err = kstrtobool(val, &enable);
+ err = kstrtobool(val, &enabled);
if (err)
return err;
- if (is_enabled == enable)
+ if (damon_lru_sort_enabled() == enabled)
return 0;
/* Called before init function. The function will handle this. */
if (!damon_initialized())
- goto set_param_out;
+ return 0;
- err = damon_lru_sort_turn(enable);
- if (err)
- return err;
+ return damon_lru_sort_turn(enabled);
+}
-set_param_out:
- enabled = enable;
- return err;
+static int damon_lru_sort_enabled_load(char *buffer,
+ const struct kernel_param *kp)
+{
+ return sprintf(buffer, "%c\n", damon_lru_sort_enabled() ? 'Y' : 'N');
}
static const struct kernel_param_ops enabled_param_ops = {
.set = damon_lru_sort_enabled_store,
- .get = param_get_bool,
+ .get = damon_lru_sort_enabled_load,
};
module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
MODULE_PARM_DESC(enabled,
"Enable or disable DAMON_LRU_SORT (default: disabled)");
+static int damon_lru_sort_kdamond_pid_store(const char *val,
+ const struct kernel_param *kp)
+{
+ /*
+ * kdamond_pid is read-only, but kernel command line could write it.
+ * Do nothing here.
+ */
+ return 0;
+}
+
+static int damon_lru_sort_kdamond_pid_load(char *buffer,
+ const struct kernel_param *kp)
+{
+ int kdamond_pid = -1;
+
+ if (ctx) {
+ kdamond_pid = damon_kdamond_pid(ctx);
+ if (kdamond_pid < 0)
+ kdamond_pid = -1;
+ }
+ return sprintf(buffer, "%d\n", kdamond_pid);
+}
+
+static const struct kernel_param_ops kdamond_pid_param_ops = {
+ .set = damon_lru_sort_kdamond_pid_store,
+ .get = damon_lru_sort_kdamond_pid_load,
+};
+
+/*
+ * PID of the DAMON thread
+ *
+ * If DAMON_LRU_SORT is enabled, this becomes the PID of the worker thread.
+ * Else, -1.
+ */
+module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400);
+
static int __init damon_lru_sort_init(void)
{
int err;
diff --git a/mm/damon/reclaim.c b/mm/damon/reclaim.c
index 86da14778658..fe7fce26cf6c 100644
--- a/mm/damon/reclaim.c
+++ b/mm/damon/reclaim.c
@@ -144,15 +144,6 @@ static unsigned long addr_unit __read_mostly = 1;
static bool skip_anon __read_mostly;
module_param(skip_anon, bool, 0600);
-/*
- * PID of the DAMON thread
- *
- * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread.
- * Else, -1.
- */
-static int kdamond_pid __read_mostly = -1;
-module_param(kdamond_pid, int, 0400);
-
static struct damos_stat damon_reclaim_stat;
DEFINE_DAMON_MODULES_DAMOS_STATS_PARAMS(damon_reclaim_stat,
reclaim_tried_regions, reclaimed_regions, quota_exceeds);
@@ -288,12 +279,8 @@ static int damon_reclaim_turn(bool on)
{
int err;
- if (!on) {
- err = damon_stop(&ctx, 1);
- if (!err)
- kdamond_pid = -1;
- return err;
- }
+ if (!on)
+ return damon_stop(&ctx, 1);
err = damon_reclaim_apply_parameters();
if (err)
@@ -302,9 +289,6 @@ static int damon_reclaim_turn(bool on)
err = damon_start(&ctx, 1, true);
if (err)
return err;
- kdamond_pid = damon_kdamond_pid(ctx);
- if (kdamond_pid < 0)
- return kdamond_pid;
return damon_call(ctx, &call_control);
}
@@ -332,42 +316,83 @@ module_param_cb(addr_unit, &addr_unit_param_ops, &addr_unit, 0600);
MODULE_PARM_DESC(addr_unit,
"Scale factor for DAMON_RECLAIM to ops address conversion (default: 1)");
+static bool damon_reclaim_enabled(void)
+{
+ if (!ctx)
+ return false;
+ return damon_is_running(ctx);
+}
+
static int damon_reclaim_enabled_store(const char *val,
const struct kernel_param *kp)
{
- bool is_enabled = enabled;
- bool enable;
int err;
- err = kstrtobool(val, &enable);
+ err = kstrtobool(val, &enabled);
if (err)
return err;
- if (is_enabled == enable)
+ if (damon_reclaim_enabled() == enabled)
return 0;
/* Called before init function. The function will handle this. */
if (!damon_initialized())
- goto set_param_out;
+ return 0;
- err = damon_reclaim_turn(enable);
- if (err)
- return err;
+ return damon_reclaim_turn(enabled);
+}
-set_param_out:
- enabled = enable;
- return err;
+static int damon_reclaim_enabled_load(char *buffer,
+ const struct kernel_param *kp)
+{
+ return sprintf(buffer, "%c\n", damon_reclaim_enabled() ? 'Y' : 'N');
}
static const struct kernel_param_ops enabled_param_ops = {
.set = damon_reclaim_enabled_store,
- .get = param_get_bool,
+ .get = damon_reclaim_enabled_load,
};
module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
MODULE_PARM_DESC(enabled,
"Enable or disable DAMON_RECLAIM (default: disabled)");
+static int damon_reclaim_kdamond_pid_store(const char *val,
+ const struct kernel_param *kp)
+{
+ /*
+ * kdamond_pid is read-only, but kernel command line could write it.
+ * Do nothing here.
+ */
+ return 0;
+}
+
+static int damon_reclaim_kdamond_pid_load(char *buffer,
+ const struct kernel_param *kp)
+{
+ int kdamond_pid = -1;
+
+ if (ctx) {
+ kdamond_pid = damon_kdamond_pid(ctx);
+ if (kdamond_pid < 0)
+ kdamond_pid = -1;
+ }
+ return sprintf(buffer, "%d\n", kdamond_pid);
+}
+
+static const struct kernel_param_ops kdamond_pid_param_ops = {
+ .set = damon_reclaim_kdamond_pid_store,
+ .get = damon_reclaim_kdamond_pid_load,
+};
+
+/*
+ * PID of the DAMON thread
+ *
+ * If DAMON_RECLAIM is enabled, this becomes the PID of the worker thread.
+ * Else, -1.
+ */
+module_param_cb(kdamond_pid, &kdamond_pid_param_ops, NULL, 0400);
+
static int __init damon_reclaim_init(void)
{
int err;
diff --git a/mm/damon/stat.c b/mm/damon/stat.c
index 99ba346f9e32..3951b762cbdd 100644
--- a/mm/damon/stat.c
+++ b/mm/damon/stat.c
@@ -19,14 +19,17 @@
static int damon_stat_enabled_store(
const char *val, const struct kernel_param *kp);
+static int damon_stat_enabled_load(char *buffer,
+ const struct kernel_param *kp);
+
static const struct kernel_param_ops enabled_param_ops = {
.set = damon_stat_enabled_store,
- .get = param_get_bool,
+ .get = damon_stat_enabled_load,
};
static bool enabled __read_mostly = IS_ENABLED(
CONFIG_DAMON_STAT_ENABLED_DEFAULT);
-module_param_cb(enabled, &enabled_param_ops, &enabled, 0600);
+module_param_cb(enabled, &enabled_param_ops, NULL, 0600);
MODULE_PARM_DESC(enabled, "Enable of disable DAMON_STAT");
static unsigned long estimated_memory_bandwidth __read_mostly;
@@ -273,17 +276,23 @@ static void damon_stat_stop(void)
damon_stat_context = NULL;
}
+static bool damon_stat_enabled(void)
+{
+ if (!damon_stat_context)
+ return false;
+ return damon_is_running(damon_stat_context);
+}
+
static int damon_stat_enabled_store(
const char *val, const struct kernel_param *kp)
{
- bool is_enabled = enabled;
int err;
err = kstrtobool(val, &enabled);
if (err)
return err;
- if (is_enabled == enabled)
+ if (damon_stat_enabled() == enabled)
return 0;
if (!damon_initialized())
@@ -293,16 +302,17 @@ static int damon_stat_enabled_store(
*/
return 0;
- if (enabled) {
- err = damon_stat_start();
- if (err)
- enabled = false;
- return err;
- }
+ if (enabled)
+ return damon_stat_start();
damon_stat_stop();
return 0;
}
+static int damon_stat_enabled_load(char *buffer, const struct kernel_param *kp)
+{
+ return sprintf(buffer, "%c\n", damon_stat_enabled() ? 'Y' : 'N');
+}
+
static int __init damon_stat_init(void)
{
int err = 0;
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index 5186966dafb3..245d63808411 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -533,9 +533,14 @@ static ssize_t memcg_path_show(struct kobject *kobj,
{
struct damon_sysfs_scheme_filter *filter = container_of(kobj,
struct damon_sysfs_scheme_filter, kobj);
+ int len;
- return sysfs_emit(buf, "%s\n",
+ if (!mutex_trylock(&damon_sysfs_lock))
+ return -EBUSY;
+ len = sysfs_emit(buf, "%s\n",
filter->memcg_path ? filter->memcg_path : "");
+ mutex_unlock(&damon_sysfs_lock);
+ return len;
}
static ssize_t memcg_path_store(struct kobject *kobj,
@@ -550,8 +555,13 @@ static ssize_t memcg_path_store(struct kobject *kobj,
return -ENOMEM;
strscpy(path, buf, count + 1);
+ if (!mutex_trylock(&damon_sysfs_lock)) {
+ kfree(path);
+ return -EBUSY;
+ }
kfree(filter->memcg_path);
filter->memcg_path = path;
+ mutex_unlock(&damon_sysfs_lock);
return count;
}
@@ -1187,8 +1197,13 @@ static ssize_t path_show(struct kobject *kobj,
{
struct damos_sysfs_quota_goal *goal = container_of(kobj,
struct damos_sysfs_quota_goal, kobj);
+ int len;
- return sysfs_emit(buf, "%s\n", goal->path ? goal->path : "");
+ if (!mutex_trylock(&damon_sysfs_lock))
+ return -EBUSY;
+ len = sysfs_emit(buf, "%s\n", goal->path ? goal->path : "");
+ mutex_unlock(&damon_sysfs_lock);
+ return len;
}
static ssize_t path_store(struct kobject *kobj,
@@ -1203,8 +1218,13 @@ static ssize_t path_store(struct kobject *kobj,
return -ENOMEM;
strscpy(path, buf, count + 1);
+ if (!mutex_trylock(&damon_sysfs_lock)) {
+ kfree(path);
+ return -EBUSY;
+ }
kfree(goal->path);
goal->path = path;
+ mutex_unlock(&damon_sysfs_lock);
return count;
}
diff --git a/mm/hugetlb_cma.c b/mm/hugetlb_cma.c
index f83ae4998990..7693ccefd0c6 100644
--- a/mm/hugetlb_cma.c
+++ b/mm/hugetlb_cma.c
@@ -204,6 +204,7 @@ void __init hugetlb_cma_reserve(void)
*/
per_node = DIV_ROUND_UP(hugetlb_cma_size,
nodes_weight(hugetlb_bootmem_nodes));
+ per_node = round_up(per_node, PAGE_SIZE << order);
pr_info("hugetlb_cma: reserve %lu MiB, up to %lu MiB per node\n",
hugetlb_cma_size / SZ_1M, per_node / SZ_1M);
}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index c3d98ab41f1f..c03d4787d466 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -805,12 +805,17 @@ static long memcg_state_val_in_pages(int idx, long val)
* Used in mod_memcg_state() and mod_memcg_lruvec_state() to avoid race with
* reparenting of non-hierarchical state_locals.
*/
-static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg)
+static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg,
+ bool *rcu_locked)
{
- if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
+ /* Rebinding can cause this value to be changed at runtime */
+ if (cgroup_subsys_on_dfl(memory_cgrp_subsys)) {
+ *rcu_locked = false;
return memcg;
+ }
rcu_read_lock();
+ *rcu_locked = true;
while (memcg_is_dying(memcg))
memcg = parent_mem_cgroup(memcg);
@@ -818,20 +823,21 @@ static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *me
return memcg;
}
-static inline void get_non_dying_memcg_end(void)
+static inline void get_non_dying_memcg_end(bool rcu_locked)
{
- if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
+ if (!rcu_locked)
return;
rcu_read_unlock();
}
#else
-static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg)
+static inline struct mem_cgroup *get_non_dying_memcg_start(struct mem_cgroup *memcg,
+ bool *rcu_locked)
{
return memcg;
}
-static inline void get_non_dying_memcg_end(void)
+static inline void get_non_dying_memcg_end(bool rcu_locked)
{
}
#endif
@@ -865,12 +871,14 @@ static void __mod_memcg_state(struct mem_cgroup *memcg,
void mod_memcg_state(struct mem_cgroup *memcg, enum memcg_stat_item idx,
int val)
{
+ bool rcu_locked = false;
+
if (mem_cgroup_disabled())
return;
- memcg = get_non_dying_memcg_start(memcg);
+ memcg = get_non_dying_memcg_start(memcg, &rcu_locked);
__mod_memcg_state(memcg, idx, val);
- get_non_dying_memcg_end();
+ get_non_dying_memcg_end(rcu_locked);
}
#ifdef CONFIG_MEMCG_V1
@@ -933,14 +941,15 @@ static void mod_memcg_lruvec_state(struct lruvec *lruvec,
struct pglist_data *pgdat = lruvec_pgdat(lruvec);
struct mem_cgroup_per_node *pn;
struct mem_cgroup *memcg;
+ bool rcu_locked = false;
pn = container_of(lruvec, struct mem_cgroup_per_node, lruvec);
- memcg = get_non_dying_memcg_start(pn->memcg);
+ memcg = get_non_dying_memcg_start(pn->memcg, &rcu_locked);
pn = memcg->nodeinfo[pgdat->node_id];
__mod_memcg_lruvec_state(pn, idx, val);
- get_non_dying_memcg_end();
+ get_non_dying_memcg_end(rcu_locked);
}
/**
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 88cd53d4ba09..833f743f309f 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -1835,7 +1835,9 @@ static int balance_dirty_pages(struct bdi_writeback *wb,
balance_domain_limits(mdtc, strictlimit);
}
- if (nr_dirty > gdtc->bg_thresh && !writeback_in_progress(wb))
+ if (!writeback_in_progress(wb) &&
+ (nr_dirty > gdtc->bg_thresh ||
+ (strictlimit && gdtc->wb_dirty > gdtc->wb_bg_thresh)))
wb_start_background_writeback(wb);
/*
@@ -1862,15 +1864,9 @@ free_running:
* Unconditionally start background writeback if it's not
* already in progress. We need to do this because the global
* dirty threshold check above (nr_dirty > gdtc->bg_thresh)
- * doesn't account for these cases:
- *
- * a) strictlimit BDIs: throttling is calculated using per-wb
- * thresholds. The per-wb threshold can be exceeded even when
- * nr_dirty < gdtc->bg_thresh
- *
- * b) memcg-based throttling: memcg uses its own dirty count and
- * thresholds and can trigger throttling even when global
- * nr_dirty < gdtc->bg_thresh
+ * doesn't account for the memcg-based throttling case. memcg
+ * uses its own dirty count and thresholds and can trigger
+ * throttling even when global nr_dirty < gdtc->bg_thresh
*
* Writeback needs to be started else the writer stalls in the
* throttle loop waiting for dirty pages to be written back
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 65e205111553..227d58dc3de6 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -7737,6 +7737,11 @@ struct page *alloc_frozen_pages_nolock_noprof(gfp_t gfp_flags, int nid, unsigned
*/
if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq()))
return NULL;
+
+ /* On UP, spin_trylock() always succeeds even when it is locked */
+ if (!IS_ENABLED(CONFIG_SMP) && in_nmi())
+ return NULL;
+
if (!pcp_allowed_order(order))
return NULL;
diff --git a/mm/slub.c b/mm/slub.c
index 161079ac5ba1..0baa906f39ab 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -5339,6 +5339,10 @@ void *kmalloc_nolock_noprof(size_t size, gfp_t gfp_flags, int node)
if (IS_ENABLED(CONFIG_PREEMPT_RT) && (in_nmi() || in_hardirq()))
return NULL;
+ /* On UP, spin_trylock() always succeeds even when it is locked */
+ if (!IS_ENABLED(CONFIG_SMP) && in_nmi())
+ return NULL;
+
retry:
if (unlikely(size > KMALLOC_MAX_CACHE_SIZE))
return NULL;
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
index 885da1e56466..180bad42fc79 100644
--- a/mm/userfaultfd.c
+++ b/mm/userfaultfd.c
@@ -443,8 +443,10 @@ static int mfill_copy_folio_locked(struct folio *folio, unsigned long src_addr)
return ret;
}
-static int mfill_copy_folio_retry(struct mfill_state *state, struct folio *folio)
+static int mfill_copy_folio_retry(struct mfill_state *state,
+ struct folio *folio)
{
+ const struct vm_uffd_ops *orig_ops = vma_uffd_ops(state->vma);
unsigned long src_addr = state->src_addr;
void *kaddr;
int err;
@@ -465,6 +467,14 @@ static int mfill_copy_folio_retry(struct mfill_state *state, struct folio *folio
if (err)
return err;
+ /*
+ * The VMA type may have changed while the lock was dropped
+ * (e.g. replaced with a hugetlb mapping), making the caller's
+ * ops pointer stale.
+ */
+ if (vma_uffd_ops(state->vma) != orig_ops)
+ return -EAGAIN;
+
err = mfill_establish_pmd(state);
if (err)
return err;
diff --git a/mm/util.c b/mm/util.c
index 232c3930a662..3cc949a0b7ed 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -1232,7 +1232,7 @@ int __compat_vma_mmap(struct vm_area_desc *desc,
/* Update the VMA from the descriptor. */
compat_set_vma_from_desc(vma, desc);
/* Complete any specified mmap actions. */
- return mmap_action_complete(vma, &desc->action);
+ return mmap_action_complete(vma, &desc->action, /*is_compat=*/true);
}
EXPORT_SYMBOL(__compat_vma_mmap);
@@ -1389,7 +1389,8 @@ static int call_vma_mapped(struct vm_area_struct *vma)
}
static int mmap_action_finish(struct vm_area_struct *vma,
- struct mmap_action *action, int err)
+ struct mmap_action *action, int err,
+ bool is_compat)
{
size_t len;
@@ -1400,8 +1401,12 @@ static int mmap_action_finish(struct vm_area_struct *vma,
/* do_munmap() might take rmap lock, so release if held. */
maybe_rmap_unlock_action(vma, action);
- if (!err)
- return 0;
+ /*
+ * If this is invoked from the compatibility layer, post-mmap() hook
+ * logic will handle cleanup for us.
+ */
+ if (!err || is_compat)
+ return err;
/*
* If an error occurs, unmap the VMA altogether and return an error. We
@@ -1451,13 +1456,15 @@ EXPORT_SYMBOL(mmap_action_prepare);
* mmap_action_complete - Execute VMA descriptor action.
* @vma: The VMA to perform the action upon.
* @action: The action to perform.
+ * @is_compat: Is this being invoked from the compatibility layer?
*
* Similar to mmap_action_prepare().
*
- * Return: 0 on success, or error, at which point the VMA will be unmapped.
+ * Return: 0 on success, or error, at which point the VMA will be unmapped if
+ * !@is_compat.
*/
int mmap_action_complete(struct vm_area_struct *vma,
- struct mmap_action *action)
+ struct mmap_action *action, bool is_compat)
{
int err = 0;
@@ -1478,7 +1485,7 @@ int mmap_action_complete(struct vm_area_struct *vma,
break;
}
- return mmap_action_finish(vma, action, err);
+ return mmap_action_finish(vma, action, err, is_compat);
}
EXPORT_SYMBOL(mmap_action_complete);
#else
@@ -1500,7 +1507,8 @@ int mmap_action_prepare(struct vm_area_desc *desc)
EXPORT_SYMBOL(mmap_action_prepare);
int mmap_action_complete(struct vm_area_struct *vma,
- struct mmap_action *action)
+ struct mmap_action *action,
+ bool is_compat)
{
int err = 0;
@@ -1517,7 +1525,7 @@ int mmap_action_complete(struct vm_area_struct *vma,
break;
}
- return mmap_action_finish(vma, action, err);
+ return mmap_action_finish(vma, action, err, is_compat);
}
EXPORT_SYMBOL(mmap_action_complete);
#endif
diff --git a/mm/vma.c b/mm/vma.c
index 377321b48734..d90791b00a7b 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -2780,7 +2780,8 @@ static unsigned long __mmap_region(struct file *file, unsigned long addr,
__mmap_complete(&map, vma);
if (have_mmap_prepare && allocated_new) {
- error = mmap_action_complete(vma, &desc.action);
+ error = mmap_action_complete(vma, &desc.action,
+ /*is_compat=*/false);
if (error)
return error;
}
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index aa08651ec0df..c31a8615a832 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -4361,7 +4361,7 @@ need_realloc:
return NULL;
if (p) {
- memcpy(n, p, old_size);
+ memcpy(n, p, min(size, old_size));
vfree(p);
}