summaryrefslogtreecommitdiff
path: root/mm/damon/core.c
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-24 16:21:27 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-07-24 16:21:27 +0200
commit8f9aa2c90530ab92301a82231ae44f3722becd93 (patch)
treefb282e955b0a880b07131a135257fe3ec764e928 /mm/damon/core.c
parent93467b31bec6da512b51544e5e4584f2745e995e (diff)
parent155b42bec9cbb6b8cdc47dd9bd09503a81fbe493 (diff)
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'mm/damon/core.c')
-rw-r--r--mm/damon/core.c59
1 files changed, 50 insertions, 9 deletions
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 3dbbbfdeff71..60f5f191e17a 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -1257,10 +1257,36 @@ static int damon_commit_target(
return 0;
}
+/*
+ * damon_revert_target_commits() - revert unsuccessful target commits.
+ * @dst: Commit destination context
+ * @failed: Commit failed destination target
+ * @src: Commit source context
+ *
+ * Revert target states that changed by damon_commit_target(), and cannot be
+ * cleaned up by the destination context's ops.cleanup_target().
+ */
+static void damon_revert_target_commits(struct damon_ctx *dst,
+ struct damon_target *failed, struct damon_ctx *src)
+{
+ struct damon_target *target;
+
+ if (!damon_target_has_pid(src))
+ return;
+ if (dst->ops.cleanup_target)
+ return;
+ damon_for_each_target(target, dst) {
+ if (target == failed)
+ return;
+ put_pid(target->pid);
+ }
+}
+
static int damon_commit_targets(
struct damon_ctx *dst, struct damon_ctx *src)
{
struct damon_target *dst_target, *next, *src_target, *new_target;
+ struct damon_target *failed;
int i = 0, j = 0, err;
damon_for_each_target_safe(dst_target, next, dst) {
@@ -1274,8 +1300,10 @@ static int damon_commit_targets(
dst_target, damon_target_has_pid(dst),
src_target, damon_target_has_pid(src),
src->min_region_sz);
- if (err)
- return err;
+ if (err) {
+ failed = dst_target;
+ goto out;
+ }
} else {
struct damos *s;
@@ -1289,25 +1317,34 @@ static int damon_commit_targets(
}
}
+ failed = NULL;
damon_for_each_target_safe(src_target, next, src) {
if (j++ < i)
continue;
/* target to remove has no matching dst */
- if (src_target->obsolete)
- return -EINVAL;
+ if (src_target->obsolete) {
+ err = -EINVAL;
+ goto out;
+ }
new_target = damon_new_target();
- if (!new_target)
- return -ENOMEM;
+ if (!new_target) {
+ err = -ENOMEM;
+ goto out;
+ }
err = damon_commit_target(new_target, false,
src_target, damon_target_has_pid(src),
src->min_region_sz);
if (err) {
damon_destroy_target(new_target, NULL);
- return err;
+ goto out;
}
damon_add_target(dst, new_target);
}
return 0;
+
+out:
+ damon_revert_target_commits(dst, failed, src);
+ return err;
}
/**
@@ -1346,8 +1383,10 @@ int damon_commit_ctx(struct damon_ctx *dst, struct damon_ctx *src)
*/
if (!damon_attrs_equals(&dst->attrs, &src->attrs)) {
err = damon_set_attrs(dst, &src->attrs);
- if (err)
+ if (err) {
+ damon_revert_target_commits(dst, NULL, src);
return err;
+ }
}
dst->ops = src->ops;
dst->addr_unit = src->addr_unit;
@@ -2106,7 +2145,7 @@ static void damos_apply_scheme(struct damon_ctx *c, struct damon_target *t,
if (damos_quota_is_set(quota) &&
quota->charged_sz >= quota->esz) {
quota->charge_target_from = t;
- quota->charge_addr_from = r->ar.end + 1;
+ quota->charge_addr_from = r->ar.end;
}
}
if (s->action != DAMOS_STAT)
@@ -2453,6 +2492,8 @@ static void damos_adjust_quota(struct damon_ctx *c, struct damos *s)
if (!quota->total_charged_sz && !quota->charged_from) {
quota->charged_from = jiffies;
damos_set_effective_quota(quota, c);
+ if (trace_damos_esz_enabled())
+ damos_trace_esz(c, s, quota);
}
/* New charge window starts */