Commit e3c33bc7 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'mm-hotfixes-stable-2026-03-23-17-56' of...

Merge tag 'mm-hotfixes-stable-2026-03-23-17-56' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm

Pull MM fixes from Andrew Morton:
 "6 hotfixes.  2 are cc:stable.  All are for MM.

  All are singletons - please see the changelogs for details"

* tag 'mm-hotfixes-stable-2026-03-23-17-56' of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm:
  mm/damon/stat: monitor all System RAM resources
  mm/zswap: add missing kunmap_local()
  mailmap: update email address for Muhammad Usama Anjum
  zram: do not slot_free() written-back slots
  mm/damon/core: avoid use of half-online-committed context
  mm/rmap: clear vma->anon_vma on error
parents 26a01984 84481e70
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -587,6 +587,7 @@ Morten Welinder <terra@gnome.org>
Morten Welinder <welinder@anemone.rentec.com>
Morten Welinder <welinder@darter.rentec.com>
Morten Welinder <welinder@troll.com>
Muhammad Usama Anjum <usama.anjum@arm.com> <usama.anjum@collabora.com>
Mukesh Ojha <quic_mojha@quicinc.com> <mojha@codeaurora.org>
Muna Sinada <quic_msinada@quicinc.com> <msinada@codeaurora.org>
Murali Nalajala <quic_mnalajal@quicinc.com> <mnalajal@codeaurora.org>
+14 −25
Original line number Diff line number Diff line
@@ -917,9 +917,8 @@ static void zram_account_writeback_submit(struct zram *zram)

static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req)
{
	u32 size, index = req->pps->index;
	int err, prio;
	bool huge;
	u32 index = req->pps->index;
	int err;

	err = blk_status_to_errno(req->bio.bi_status);
	if (err) {
@@ -946,28 +945,13 @@ static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req)
		goto out;
	}

	if (zram->compressed_wb) {
		/*
		 * ZRAM_WB slots get freed, we need to preserve data required
		 * for read decompression.
		 */
		size = get_slot_size(zram, index);
		prio = get_slot_comp_priority(zram, index);
		huge = test_slot_flag(zram, index, ZRAM_HUGE);
	}

	slot_free(zram, index);
	set_slot_flag(zram, index, ZRAM_WB);
	clear_slot_flag(zram, index, ZRAM_IDLE);
	if (test_slot_flag(zram, index, ZRAM_HUGE))
		atomic64_dec(&zram->stats.huge_pages);
	atomic64_sub(get_slot_size(zram, index), &zram->stats.compr_data_size);
	zs_free(zram->mem_pool, get_slot_handle(zram, index));
	set_slot_handle(zram, index, req->blk_idx);

	if (zram->compressed_wb) {
		if (huge)
			set_slot_flag(zram, index, ZRAM_HUGE);
		set_slot_size(zram, index, size);
		set_slot_comp_priority(zram, index, prio);
	}

	atomic64_inc(&zram->stats.pages_stored);
	set_slot_flag(zram, index, ZRAM_WB);

out:
	slot_unlock(zram, index);
@@ -2010,8 +1994,13 @@ static void slot_free(struct zram *zram, u32 index)
	set_slot_comp_priority(zram, index, 0);

	if (test_slot_flag(zram, index, ZRAM_HUGE)) {
		clear_slot_flag(zram, index, ZRAM_HUGE);
		/*
		 * Writeback completion decrements ->huge_pages but keeps
		 * ZRAM_HUGE flag for deferred decompression path.
		 */
		if (!test_slot_flag(zram, index, ZRAM_WB))
			atomic64_dec(&zram->stats.huge_pages);
		clear_slot_flag(zram, index, ZRAM_HUGE);
	}

	if (test_slot_flag(zram, index, ZRAM_WB)) {
+6 −0
Original line number Diff line number Diff line
@@ -810,6 +810,12 @@ struct damon_ctx {
	struct damos_walk_control *walk_control;
	struct mutex walk_control_lock;

	/*
	 * indicate if this may be corrupted.  Currentonly this is set only for
	 * damon_commit_ctx() failure.
	 */
	bool maybe_corrupted;

	/* Working thread of the given DAMON context */
	struct task_struct *kdamond;
	/* Protects @kdamond field access */
+8 −0
Original line number Diff line number Diff line
@@ -1252,6 +1252,7 @@ int damon_commit_ctx(struct damon_ctx *dst, struct damon_ctx *src)
{
	int err;

	dst->maybe_corrupted = true;
	if (!is_power_of_2(src->min_region_sz))
		return -EINVAL;

@@ -1277,6 +1278,7 @@ int damon_commit_ctx(struct damon_ctx *dst, struct damon_ctx *src)
	dst->addr_unit = src->addr_unit;
	dst->min_region_sz = src->min_region_sz;

	dst->maybe_corrupted = false;
	return 0;
}

@@ -2678,6 +2680,8 @@ static void kdamond_call(struct damon_ctx *ctx, bool cancel)
			complete(&control->completion);
		else if (control->canceled && control->dealloc_on_cancel)
			kfree(control);
		if (!cancel && ctx->maybe_corrupted)
			break;
	}

	mutex_lock(&ctx->call_controls_lock);
@@ -2707,6 +2711,8 @@ static int kdamond_wait_activation(struct damon_ctx *ctx)
		kdamond_usleep(min_wait_time);

		kdamond_call(ctx, false);
		if (ctx->maybe_corrupted)
			return -EINVAL;
		damos_walk_cancel(ctx);
	}
	return -EBUSY;
@@ -2790,6 +2796,8 @@ static int kdamond_fn(void *data)
		 * kdamond_merge_regions() if possible, to reduce overhead
		 */
		kdamond_call(ctx, false);
		if (ctx->maybe_corrupted)
			break;
		if (!list_empty(&ctx->schemes))
			kdamond_apply_schemes(ctx);
		else
+50 −3
Original line number Diff line number Diff line
@@ -145,12 +145,59 @@ static int damon_stat_damon_call_fn(void *data)
	return 0;
}

struct damon_stat_system_ram_range_walk_arg {
	bool walked;
	struct resource res;
};

static int damon_stat_system_ram_walk_fn(struct resource *res, void *arg)
{
	struct damon_stat_system_ram_range_walk_arg *a = arg;

	if (!a->walked) {
		a->walked = true;
		a->res.start = res->start;
	}
	a->res.end = res->end;
	return 0;
}

static unsigned long damon_stat_res_to_core_addr(resource_size_t ra,
		unsigned long addr_unit)
{
	/*
	 * Use div_u64() for avoiding linking errors related with __udivdi3,
	 * __aeabi_uldivmod, or similar problems.  This should also improve the
	 * performance optimization (read div_u64() comment for the detail).
	 */
	if (sizeof(ra) == 8 && sizeof(addr_unit) == 4)
		return div_u64(ra, addr_unit);
	return ra / addr_unit;
}

static int damon_stat_set_monitoring_region(struct damon_target *t,
		unsigned long addr_unit, unsigned long min_region_sz)
{
	struct damon_addr_range addr_range;
	struct damon_stat_system_ram_range_walk_arg arg = {};

	walk_system_ram_res(0, -1, &arg, damon_stat_system_ram_walk_fn);
	if (!arg.walked)
		return -EINVAL;
	addr_range.start = damon_stat_res_to_core_addr(
			arg.res.start, addr_unit);
	addr_range.end = damon_stat_res_to_core_addr(
			arg.res.end + 1, addr_unit);
	if (addr_range.end <= addr_range.start)
		return -EINVAL;
	return damon_set_regions(t, &addr_range, 1, min_region_sz);
}

static struct damon_ctx *damon_stat_build_ctx(void)
{
	struct damon_ctx *ctx;
	struct damon_attrs attrs;
	struct damon_target *target;
	unsigned long start = 0, end = 0;

	ctx = damon_new_ctx();
	if (!ctx)
@@ -180,7 +227,7 @@ static struct damon_ctx *damon_stat_build_ctx(void)
	if (!target)
		goto free_out;
	damon_add_target(ctx, target);
	if (damon_set_region_biggest_system_ram_default(target, &start, &end,
	if (damon_stat_set_monitoring_region(target, ctx->addr_unit,
				ctx->min_region_sz))
		goto free_out;
	return ctx;
Loading