* [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions
@ 2025-07-02 20:13 Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 01/13] mm/damon: add struct damos_migrate_dests Bijan Tabatabai
` (13 more replies)
0 siblings, 14 replies; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr
From: Bijan Tabatabai <bijantabatab@micron.com>
A recent patch set automatically sets the interleave weight for each node
according to the node's maximum bandwidth [1]. In another thread, the patch
set's author, Joshua Hahn, wondered if/how thes weights should be changed
if the bandwidth utilization of the system changes [2].
This patch set adds the mechanism for dynamically changing how application
data is interleaved across nodes while leaving the policy of what the
interleave weights should be to userspace. It does this by having the
migrate_{hot,cold} operating schemes interleave application data according
to the list of migration nodes and weights passed in via the DAMON sysfs
interface. This functionality can be used to dynamically adjust how folios
are interleaved by having a userspace process adjust those weights. If no
specific destination nodes or weights are provided, the migrate_{hot,cold}
actions will only migrate folios to damos->target_nid as before.
The algorithm used to interleave the folios is similar to the one used for
the weighted interleave mempolicy [3]. It uses the offset from which a
folio is mapped into a VMA to determine the node the folio should be placed
in. This method is convenient because for a given set of interleave
weights, a folio has only one valid node it can be placed in, limitng the
amount of unnecessary data movement. However, finding out how a folio is
mapped inside of a VMA requires a costly rmap walk when using a paddr
scheme. As such, we have decided that this functionality makes more sense
as a vaddr scheme [4]. To this end, this patch set also adds vaddr versions
of the migrate_{hot,cold}.
Motivation
==========
There have been prior discussions about how changing the interleave weights
in response to the system's bandwidth utilization can be beneficial [2].
However, currently the interleave weights only are applied when data is
allocated. Migrating already allocated pages according to the dynamically
changing weights will better help balance the bandwidth utilization across
nodes.
As a toy example, imagine some application that uses 75% of the local
bandwidth. Assuming sufficient capacity, when running alone, we want to
keep that application's data in local memory. However, if a second
instance of that application begins, using the same amount of bandwidth,
it would be best to interleave the data of both processes to alleviate the
bandwidth pressure from the local node. Likewise, when one of the processes
ends, the data should be moves back to local memory.
We imagine there would be a userspace application that would monitor system
performance characteristics, such as bandwidth utilization or memory access
latency, and uses that information to tune the interleave weights. Others
seem to have come to a similar conclusion in previous discussions [5].
We are currently working on a userspace program that does this, but it is
not quite ready to be published yet.
After the userspace application tunes the interleave weights, there must be
some mechanism that actually migrates pages to be consistent with those
weights. This patchset is what provides this mechanism.
We believe DAMON is the correct venue for the interleaving mechanism for a
few reasons. First, we noticed that we don't have to migrate all of the
application's pages to improve performance. we just need to migrate the
frequently accessed pages. DAMON's existing hotness traching is very useful
for this. Second, DAMON's quota system can be used to ensure we are not
using too much bandwidth for migrations. Finally, as Ying pointed out [6],
a complete solution must also handle when a memory node is at capacity. The
existing migrate_cold action can be used in conjunction with the
functionality added in this patch set to provide that complete solution.
Functionality Test
==================
Below is an example of this new functionality in use to confirm that these
patches behave as intended.
In this example, the user starts an application, alloc_data, which
allocates 1GB using the default memory policy (i.e. allocate to local
memory) then sleeps. Afterwards, we start DAMON to interleave the data at a
1:1 ratio. Using numastat, we show that DAMON has migrated the
application's data to match the new interleave ratio.
For this example, I modified the userspace damo tool [8] to write to the
migration_dest sysfs files. I plan to upstream these changes when these
patches are merged.
$ # Allocate the data initially
$ ./alloc_data 1G &
[1] 6587
$ numastat -c -p alloc_data
Per-node process memory usage (in MBs) for PID 6587 (alloc_data)
Node 0 Node 1 Total
------ ------ -----
Huge 0 0 0
Heap 0 0 0
Stack 0 0 0
Private 1027 0 1027
------- ------ ------ -----
Total 1027 0 1027
$ # Start DAMON to interleave data at a 1:1 ratio
$ cat ./interleave_vaddr.yaml
kdamonds:
- contexts:
- ops: vaddr
addr_unit: null
targets:
- pid: 6587
regions: []
intervals:
sample_us: 500 ms
aggr_us: 5 s
ops_update_us: 20 s
intervals_goal:
access_bp: 0 %
aggrs: '0'
min_sample_us: 0 ns
max_sample_us: 0 ns
nr_regions:
min: '20'
max: '50'
schemes:
- action: migrate_hot
dests:
- nid: 0
weight: 1
- nid: 1
weight: 1
access_pattern:
sz_bytes:
min: 0 B
max: max
nr_accesses:
min: 0 %
max: 100 %
age:
min: 0 ns
max: max
$ sudo ./damo/damo interleave_vaddr.yaml
$ # Verify that DAMON has migrated data to match the 1:1 ratio
$ numastat -c -p alloc_data
Per-node process memory usage (in MBs) for PID 6587 (alloc_data)
Node 0 Node 1 Total
------ ------ -----
Huge 0 0 0
Heap 0 0 0
Stack 0 0 0
Private 514 514 1027
------- ------ ------ -----
Total 514 514 1027
Performance Test
================
Below is a simple example showing that interleaving application data using
these patches can improve application performance.
To do this, we run a bandwidth intensive embedding reduction application
[7]. This workload is useful for this test because it reports the time it
takes each iteration to run and each iteration reuses the same allocation,
allowing us to see the benefits of the migration.
We evaluate this on a 128 core/256 thread AMD CPU with 72GB/s of local DDR
bandwidth and 26 GB/s of CXL bandwidth.
Before we start the workload, the system bandwidth utilization is low, so
we start with the interleave weights of 1:0, i.e. allocating all data to
local memory. When the workload beings, it saturates the local bandwidth,
making the page placement suboptimal. To alleviate this, we modify the
interleave weights, triggering DAMON to migrate the workload's data.
We use the same interleave_vaddr.yaml file to setup DAMON, except we
configure it to begin with a 1:0 interleave ratio, and attach it to the
shell and its children processes.
$ sudo ./damo/damo start interleave_vaddr.yaml --include_child_tasks &
$ <path>/eval_baseline -d amazon_All -c 255 -r 100
<clip startup output>
Eval Phase 3: Running Baseline...
REPEAT # 0 Baseline Total time : 7323.54 ms
REPEAT # 1 Baseline Total time : 7624.56 ms
REPEAT # 2 Baseline Total time : 7619.61 ms
REPEAT # 3 Baseline Total time : 7617.12 ms
REPEAT # 4 Baseline Total time : 7638.64 ms
REPEAT # 5 Baseline Total time : 7611.27 ms
REPEAT # 6 Baseline Total time : 7629.32 ms
REPEAT # 7 Baseline Total time : 7695.63 ms
# Interleave weights set to 3:1
REPEAT # 8 Baseline Total time : 7077.5 ms
REPEAT # 9 Baseline Total time : 5633.23 ms
REPEAT # 10 Baseline Total time : 5644.6 ms
REPEAT # 11 Baseline Total time : 5627.66 ms
REPEAT # 12 Baseline Total time : 5629.76 ms
REPEAT # 13 Baseline Total time : 5633.05 ms
REPEAT # 14 Baseline Total time : 5641.24 ms
REPEAT # 15 Baseline Total time : 5631.18 ms
REPEAT # 16 Baseline Total time : 5631.33 ms
Updating the interleave weights and having DAMON migrate the workload data
according to the weights resulted in an approximarely 25% speedup.
Patches Sequence
================
Patches 1-7 extend the DAMON API to specify multiple destination nodes and
weights for the migrate_{hot,cold} actions. These patches are from SJ'S
RFC [8].
Patches 8-10 add a vaddr implementation of the migrate_{hot,cold} schemes.
Patch 11 modifies the vaddr migrate_{hot,cold} schemes to interleave data
according to the weights provided by damos->migrate_dest.
Patches 12-13 allow the vaddr migrate_{hot,cold} implementation to filter
out folios like the paddr version.
Revision History
================
Changes from v2 [9]:
- Implement interleaving using vaddr instead of paddr
- Add vaddr implementation of migrate_{hot,cold}
- Use DAMON specific interleave weights instead of mempolicy weights
Changes from v1 [10]:
- Reuse migrate_{hot,cold} actions instead of creating a new action
- Remove vaddr implementation
- Remove most of the use of mempolicy, instead duplicate the interleave
logic and access interleave weights directly
- Write more about the use case in the cover letter
- Write about why DAMON was used for this in the cover letter
- Add correctness test to the cover letter
- Add performance test
[1] https://lore.kernel.org/linux-mm/20250520141236.2987309-1-joshua.hahnjy@gmail.com/
[2] https://lore.kernel.org/linux-mm/20250313155705.1943522-1-joshua.hahnjy@gmail.com/
[3] https://elixir.bootlin.com/linux/v6.15.4/source/mm/mempolicy.c#L2015
[4] https://lore.kernel.org/damon/20250624223310.55786-1-sj@kernel.org/
[5] https://lore.kernel.org/linux-mm/20250314151137.892379-1-joshua.hahnjy@gmail.com/
[6] https://lore.kernel.org/linux-mm/87frjfx6u4.fsf@DESKTOP-5N7EMDA/
[7] https://github.com/SNU-ARC/MERCI
[8] https://lore.kernel.org/damon/20250702051558.54138-1-sj@kernel.org/
[9] https://lore.kernel.org/damon/20250620180458.5041-1-bijan311@gmail.com/
[10] https://lore.kernel.org/linux-mm/20250612181330.31236-1-bijan311@gmail.com/
P.S., I will be out of office Thursday until next week Tuesday, so please
forgive any delayed responses.
Bijan Tabatabai (7):
mm/damon/core: Commit damos->target_nid/migrate_dests
mm/damon: Move migration helpers from paddr to ops-common
mm/damon/vaddr: Add vaddr versions of migrate_{hot,cold}
Docs/mm/damon/design: Document vaddr support for migrate_{hot,cold}
mm/damon/vaddr: Use damos->migrate_dests in migrate_{hot,cold}
mm/damon: Move folio filtering from paddr to ops-common
mm/damon/vaddr: Apply filters in migrate_{hot/cold}
SeongJae Park (6):
mm/damon: add struct damos_migrate_dests
mm/damon/core: add damos->migrate_dests field
mm/damon/sysfs-schemes: implement DAMOS action destinations directory
mm/damon/sysfs-schemes: set damos->migrate_dests
Docs/ABI/damon: document schemes dests directory
Docs/admin-guide/mm/damon/usage: document dests directory
.../ABI/testing/sysfs-kernel-mm-damon | 22 ++
Documentation/admin-guide/mm/damon/usage.rst | 33 ++-
Documentation/mm/damon/design.rst | 4 +-
include/linux/damon.h | 29 +-
mm/damon/core.c | 44 +++
mm/damon/ops-common.c | 270 +++++++++++++++++
mm/damon/ops-common.h | 5 +
mm/damon/paddr.c | 275 +-----------------
mm/damon/sysfs-schemes.c | 253 +++++++++++++++-
mm/damon/vaddr.c | 246 ++++++++++++++++
10 files changed, 898 insertions(+), 283 deletions(-)
--
2.43.5
^ permalink raw reply [flat|nested] 25+ messages in thread
* [RFC PATCH v3 01/13] mm/damon: add struct damos_migrate_dests
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 02/13] mm/damon/core: add damos->migrate_dests field Bijan Tabatabai
` (12 subsequent siblings)
13 siblings, 0 replies; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr
From: SeongJae Park <sj@kernel.org>
Introduce a new struct, namely damos_migrate_dests, for specifying
multiple DAMOS' migration destination nodes and their weights.
Signed-off-by: SeongJae Park <sj@kernel.org>
Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
---
include/linux/damon.h | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index bb58e36f019e..24d387a972dd 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -447,6 +447,22 @@ struct damos_access_pattern {
unsigned int max_age_region;
};
+/**
+ * struct damos_migrate_dests - Migration destination nodes and their weights.
+ * @node_id_arr: Array of migration destination node ids.
+ * @weight_arr: Array of migration weights for @node_id_arr.
+ * @nr_dests: Length of the @node_id_arr and @weight_arr arrays.
+ *
+ * @node_id_arr is an array of the ids of migration destination nodes.
+ * @weight_arr is an array of the weights for those. The weights in
+ * @weight_arr are for nodes in @node_id_arr of same array index.
+ */
+struct damos_migrate_dests {
+ unsigned int *node_id_arr;
+ unsigned int *weight_arr;
+ size_t nr_dests;
+};
+
/**
* struct damos - Represents a Data Access Monitoring-based Operation Scheme.
* @pattern: Access pattern of target regions.
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 02/13] mm/damon/core: add damos->migrate_dests field
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 01/13] mm/damon: add struct damos_migrate_dests Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 03/13] mm/damon/sysfs-schemes: implement DAMOS action destinations directory Bijan Tabatabai
` (11 subsequent siblings)
13 siblings, 0 replies; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr
From: SeongJae Park <sj@kernel.org>
Add a new field to 'struct damos', namely migrate_dests, to allow DAMON
API callers specify multiple migration destination nodes and their
weights. Also update 'struct damos' creation and destruction functions
accordingly to initialize the new field and free up the API
caller-allocated buffers on those, respectively.
Signed-off-by: SeongJae Park <sj@kernel.org>
Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
---
include/linux/damon.h | 13 ++++++++++---
mm/damon/core.c | 4 ++++
2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index 24d387a972dd..6f0b0806236d 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -470,6 +470,7 @@ struct damos_migrate_dests {
* @apply_interval_us: The time between applying the @action.
* @quota: Control the aggressiveness of this scheme.
* @wmarks: Watermarks for automated (in)activation of this scheme.
+ * @migrate_dests: Destination nodes if @action is "migrate_{hot,cold}".
* @target_nid: Destination node if @action is "migrate_{hot,cold}".
* @filters: Additional set of &struct damos_filter for &action.
* @ops_filters: ops layer handling &struct damos_filter objects list.
@@ -488,9 +489,12 @@ struct damos_migrate_dests {
* monitoring context are inactive, DAMON stops monitoring either, and just
* repeatedly checks the watermarks.
*
+ * @migrate_dests specifies multiple migration target nodes with different
+ * weights for migrate_hot or migrate_cold actions. @target_nid is ignored if
+ * this is set.
+ *
* @target_nid is used to set the migration target node for migrate_hot or
- * migrate_cold actions, which means it's only meaningful when @action is either
- * "migrate_hot" or "migrate_cold".
+ * migrate_cold actions, and @migrate_dests is unset.
*
* Before applying the &action to a memory region, &struct damon_operations
* implementation could check pages of the region and skip &action to respect
@@ -533,7 +537,10 @@ struct damos {
struct damos_quota quota;
struct damos_watermarks wmarks;
union {
- int target_nid;
+ struct {
+ int target_nid;
+ struct damos_migrate_dests migrate_dests;
+ };
};
struct list_head filters;
struct list_head ops_filters;
diff --git a/mm/damon/core.c b/mm/damon/core.c
index bc2e58c1222d..a4c3cfe531df 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -407,6 +407,7 @@ struct damos *damon_new_scheme(struct damos_access_pattern *pattern,
scheme->wmarks = *wmarks;
scheme->wmarks.activated = true;
+ scheme->migrate_dests = (struct damos_migrate_dests){};
scheme->target_nid = target_nid;
return scheme;
@@ -449,6 +450,9 @@ void damon_destroy_scheme(struct damos *s)
damos_for_each_filter_safe(f, next, s)
damos_destroy_filter(f);
+
+ kfree(s->migrate_dests.node_id_arr);
+ kfree(s->migrate_dests.weight_arr);
damon_del_scheme(s);
damon_free_scheme(s);
}
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 03/13] mm/damon/sysfs-schemes: implement DAMOS action destinations directory
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 01/13] mm/damon: add struct damos_migrate_dests Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 02/13] mm/damon/core: add damos->migrate_dests field Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 04/13] mm/damon/sysfs-schemes: set damos->migrate_dests Bijan Tabatabai
` (10 subsequent siblings)
13 siblings, 0 replies; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr
From: SeongJae Park <sj@kernel.org>
DAMOS_MIGRATE_{HOT,COLD} can have multiple action destinations and their
weights. Implement sysfs directory named 'dests' under each scheme
directory to let DAMON sysfs ABI users utilize the feature. The
interface is similar to other multiple parameters directory like
kdamonds or filters. The directory contains only nr_dests file
initially. Writing a number of desired destinations to nr_dests creates
directories of the number. Each of the created directories has two
files named id and weight. Users can then write the destination's
identifier (node id in case of DAMOS_MIGRATE_*) and weight to the files.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
mm/damon/sysfs-schemes.c | 225 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 224 insertions(+), 1 deletion(-)
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index 601360e9b521..b9434cdaacdc 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -1655,6 +1655,204 @@ static const struct kobj_type damon_sysfs_access_pattern_ktype = {
.default_groups = damon_sysfs_access_pattern_groups,
};
+/*
+ * dest (action destination) directory
+ */
+
+struct damos_sysfs_dest {
+ struct kobject kobj;
+ unsigned int id;
+ unsigned int weight;
+};
+
+static struct damos_sysfs_dest *damos_sysfs_dest_alloc(void)
+{
+ return kzalloc(sizeof(struct damos_sysfs_dest), GFP_KERNEL);
+}
+
+static ssize_t id_show(
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct damos_sysfs_dest *dest = container_of(kobj,
+ struct damos_sysfs_dest, kobj);
+
+ return sysfs_emit(buf, "%u\n", dest->id);
+}
+
+static ssize_t id_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damos_sysfs_dest *dest = container_of(kobj,
+ struct damos_sysfs_dest, kobj);
+ int err = kstrtouint(buf, 0, &dest->id);
+
+ return err ? err : count;
+}
+
+static ssize_t weight_show(
+ struct kobject *kobj, struct kobj_attribute *attr, char *buf)
+{
+ struct damos_sysfs_dest *dest = container_of(kobj,
+ struct damos_sysfs_dest, kobj);
+
+ return sysfs_emit(buf, "%u\n", dest->weight);
+}
+
+static ssize_t weight_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damos_sysfs_dest *dest = container_of(kobj,
+ struct damos_sysfs_dest, kobj);
+ int err = kstrtouint(buf, 0, &dest->weight);
+
+ return err ? err : count;
+}
+
+static void damos_sysfs_dest_release(struct kobject *kobj)
+{
+ struct damos_sysfs_dest *dest = container_of(kobj,
+ struct damos_sysfs_dest, kobj);
+ kfree(dest);
+}
+
+static struct kobj_attribute damos_sysfs_dest_id_attr =
+ __ATTR_RW_MODE(id, 0600);
+
+static struct kobj_attribute damos_sysfs_dest_weight_attr =
+ __ATTR_RW_MODE(weight, 0600);
+
+static struct attribute *damos_sysfs_dest_attrs[] = {
+ &damos_sysfs_dest_id_attr.attr,
+ &damos_sysfs_dest_weight_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(damos_sysfs_dest);
+
+static const struct kobj_type damos_sysfs_dest_ktype = {
+ .release = damos_sysfs_dest_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damos_sysfs_dest_groups,
+};
+
+/*
+ * dests (action destinations) directory
+ */
+
+struct damos_sysfs_dests {
+ struct kobject kobj;
+ struct damos_sysfs_dest **dests_arr;
+ int nr;
+};
+
+static struct damos_sysfs_dests *
+damos_sysfs_dests_alloc(void)
+{
+ return kzalloc(sizeof(struct damos_sysfs_dests), GFP_KERNEL);
+}
+
+static void damos_sysfs_dests_rm_dirs(
+ struct damos_sysfs_dests *dests)
+{
+ struct damos_sysfs_dest **dests_arr = dests->dests_arr;
+ int i;
+
+ for (i = 0; i < dests->nr; i++)
+ kobject_put(&dests_arr[i]->kobj);
+ dests->nr = 0;
+ kfree(dests_arr);
+ dests->dests_arr = NULL;
+}
+
+static int damos_sysfs_dests_add_dirs(
+ struct damos_sysfs_dests *dests, int nr_dests)
+{
+ struct damos_sysfs_dest **dests_arr, *dest;
+ int err, i;
+
+ damos_sysfs_dests_rm_dirs(dests);
+ if (!nr_dests)
+ return 0;
+
+ dests_arr = kmalloc_array(nr_dests, sizeof(*dests_arr),
+ GFP_KERNEL | __GFP_NOWARN);
+ if (!dests_arr)
+ return -ENOMEM;
+ dests->dests_arr = dests_arr;
+
+ for (i = 0; i < nr_dests; i++) {
+ dest = damos_sysfs_dest_alloc();
+ if (!dest) {
+ damos_sysfs_dests_rm_dirs(dests);
+ return -ENOMEM;
+ }
+
+ err = kobject_init_and_add(&dest->kobj,
+ &damos_sysfs_dest_ktype,
+ &dests->kobj, "%d", i);
+ if (err) {
+ kobject_put(&dest->kobj);
+ damos_sysfs_dests_rm_dirs(dests);
+ return err;
+ }
+
+ dests_arr[i] = dest;
+ dests->nr++;
+ }
+ return 0;
+}
+
+static ssize_t nr_dests_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damos_sysfs_dests *dests = container_of(kobj,
+ struct damos_sysfs_dests, kobj);
+
+ return sysfs_emit(buf, "%d\n", dests->nr);
+}
+
+static ssize_t nr_dests_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damos_sysfs_dests *dests;
+ int nr, err = kstrtoint(buf, 0, &nr);
+
+ if (err)
+ return err;
+ if (nr < 0)
+ return -EINVAL;
+
+ dests = container_of(kobj, struct damos_sysfs_dests, kobj);
+
+ if (!mutex_trylock(&damon_sysfs_lock))
+ return -EBUSY;
+ err = damos_sysfs_dests_add_dirs(dests, nr);
+ mutex_unlock(&damon_sysfs_lock);
+ if (err)
+ return err;
+
+ return count;
+}
+
+static void damos_sysfs_dests_release(struct kobject *kobj)
+{
+ kfree(container_of(kobj, struct damos_sysfs_dests, kobj));
+}
+
+static struct kobj_attribute damos_sysfs_dests_nr_attr =
+ __ATTR_RW_MODE(nr_dests, 0600);
+
+static struct attribute *damos_sysfs_dests_attrs[] = {
+ &damos_sysfs_dests_nr_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(damos_sysfs_dests);
+
+static const struct kobj_type damos_sysfs_dests_ktype = {
+ .release = damos_sysfs_dests_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damos_sysfs_dests_groups,
+};
+
/*
* scheme directory
*/
@@ -1672,6 +1870,7 @@ struct damon_sysfs_scheme {
struct damon_sysfs_stats *stats;
struct damon_sysfs_scheme_regions *tried_regions;
int target_nid;
+ struct damos_sysfs_dests *dests;
};
struct damos_sysfs_action_name {
@@ -1762,6 +1961,22 @@ static int damon_sysfs_scheme_set_access_pattern(
return err;
}
+static int damos_sysfs_set_dests(struct damon_sysfs_scheme *scheme)
+{
+ struct damos_sysfs_dests *dests = damos_sysfs_dests_alloc();
+ int err;
+
+ if (!dests)
+ return -ENOMEM;
+ err = kobject_init_and_add(&dests->kobj, &damos_sysfs_dests_ktype,
+ &scheme->kobj, "dests");
+ if (err)
+ kobject_put(&dests->kobj);
+ else
+ scheme->dests = dests;
+ return err;
+}
+
static int damon_sysfs_scheme_set_quotas(struct damon_sysfs_scheme *scheme)
{
struct damon_sysfs_quotas *quotas = damon_sysfs_quotas_alloc();
@@ -1894,9 +2109,12 @@ static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme)
err = damon_sysfs_scheme_set_access_pattern(scheme);
if (err)
return err;
- err = damon_sysfs_scheme_set_quotas(scheme);
+ err = damos_sysfs_set_dests(scheme);
if (err)
goto put_access_pattern_out;
+ err = damon_sysfs_scheme_set_quotas(scheme);
+ if (err)
+ goto put_dests_out;
err = damon_sysfs_scheme_set_watermarks(scheme);
if (err)
goto put_quotas_access_pattern_out;
@@ -1927,6 +2145,9 @@ static int damon_sysfs_scheme_add_dirs(struct damon_sysfs_scheme *scheme)
put_quotas_access_pattern_out:
kobject_put(&scheme->quotas->kobj);
scheme->quotas = NULL;
+put_dests_out:
+ kobject_put(&scheme->dests->kobj);
+ scheme->dests = NULL;
put_access_pattern_out:
kobject_put(&scheme->access_pattern->kobj);
scheme->access_pattern = NULL;
@@ -1937,6 +2158,8 @@ static void damon_sysfs_scheme_rm_dirs(struct damon_sysfs_scheme *scheme)
{
damon_sysfs_access_pattern_rm_dirs(scheme->access_pattern);
kobject_put(&scheme->access_pattern->kobj);
+ kobject_put(&scheme->dests->kobj);
+ damos_sysfs_dests_rm_dirs(scheme->dests);
damon_sysfs_quotas_rm_dirs(scheme->quotas);
kobject_put(&scheme->quotas->kobj);
kobject_put(&scheme->watermarks->kobj);
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 04/13] mm/damon/sysfs-schemes: set damos->migrate_dests
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
` (2 preceding siblings ...)
2025-07-02 20:13 ` [RFC PATCH v3 03/13] mm/damon/sysfs-schemes: implement DAMOS action destinations directory Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 05/13] Docs/ABI/damon: document schemes dests directory Bijan Tabatabai
` (9 subsequent siblings)
13 siblings, 0 replies; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr
From: SeongJae Park <sj@kernel.org>
Pass user-specified multiple DAMOS action destinations and their weights
to DAMON core API, so that user requests can really work.
Signed-off-by: SeongJae Park <sj@kernel.org>
Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
---
mm/damon/sysfs-schemes.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/mm/damon/sysfs-schemes.c b/mm/damon/sysfs-schemes.c
index b9434cdaacdc..74056bcd6a2c 100644
--- a/mm/damon/sysfs-schemes.c
+++ b/mm/damon/sysfs-schemes.c
@@ -2576,6 +2576,29 @@ void damos_sysfs_update_effective_quotas(
}
}
+static int damos_sysfs_add_migrate_dest(struct damos *scheme,
+ struct damos_sysfs_dests *sysfs_dests)
+{
+ struct damos_migrate_dests *dests = &scheme->migrate_dests;
+ int i;
+
+ dests->node_id_arr = kmalloc_array(sysfs_dests->nr,
+ sizeof(*dests->node_id_arr), GFP_KERNEL);
+ if (!dests->node_id_arr)
+ return -ENOMEM;
+ dests->weight_arr = kmalloc_array(sysfs_dests->nr,
+ sizeof(*dests->weight_arr), GFP_KERNEL);
+ if (!dests->weight_arr)
+ /* ->node_id_arr will be freed by scheme destruction */
+ return -ENOMEM;
+ for (i = 0; i < sysfs_dests->nr; i++) {
+ dests->node_id_arr[i] = sysfs_dests->dests_arr[i]->id;
+ dests->weight_arr[i] = sysfs_dests->dests_arr[i]->weight;
+ }
+ dests->nr_dests = sysfs_dests->nr;
+ return 0;
+}
+
static struct damos *damon_sysfs_mk_scheme(
struct damon_sysfs_scheme *sysfs_scheme)
{
@@ -2638,6 +2661,11 @@ static struct damos *damon_sysfs_mk_scheme(
damon_destroy_scheme(scheme);
return NULL;
}
+ err = damos_sysfs_add_migrate_dest(scheme, sysfs_scheme->dests);
+ if (err) {
+ damon_destroy_scheme(scheme);
+ return NULL;
+ }
return scheme;
}
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 05/13] Docs/ABI/damon: document schemes dests directory
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
` (3 preceding siblings ...)
2025-07-02 20:13 ` [RFC PATCH v3 04/13] mm/damon/sysfs-schemes: set damos->migrate_dests Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 06/13] Docs/admin-guide/mm/damon/usage: document " Bijan Tabatabai
` (8 subsequent siblings)
13 siblings, 0 replies; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr
From: SeongJae Park <sj@kernel.org>
Document the new DAMOS action destinations sysfs directories on ABI doc.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
.../ABI/testing/sysfs-kernel-mm-damon | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/Documentation/ABI/testing/sysfs-kernel-mm-damon b/Documentation/ABI/testing/sysfs-kernel-mm-damon
index 5697ab154c1f..e98974dfac7a 100644
--- a/Documentation/ABI/testing/sysfs-kernel-mm-damon
+++ b/Documentation/ABI/testing/sysfs-kernel-mm-damon
@@ -431,6 +431,28 @@ Description: Directory for DAMON operations set layer-handled DAMOS filters.
/sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/filters
directory.
+What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/dests/nr_dests
+Date: Jul 2025
+Contact: SeongJae Park <sj@kernel.org>
+Description: Writing a number 'N' to this file creates the number of
+ directories for setting action destinations of the scheme named
+ '0' to 'N-1' under the dests/ directory.
+
+What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/dests/<D>/id
+Date: Jul 2025
+Contact: SeongJae Park <sj@kernel.org>
+Description: Writing to and reading from this file sets and gets the id of
+ the DAMOS action destination. For DAMOS_MIGRATE_{HOT,COLD}
+ actions, the destination node's node id can be written and
+ read.
+
+What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/dests/<D>/weight
+Date: Jul 2025
+Contact: SeongJae Park <sj@kernel.org>
+Description: Writing to and reading from this file sets and gets the weight
+ of the DAMOS action destination to select as the destination of
+ each action among the destinations.
+
What: /sys/kernel/mm/damon/admin/kdamonds/<K>/contexts/<C>/schemes/<S>/stats/nr_tried
Date: Mar 2022
Contact: SeongJae Park <sj@kernel.org>
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 06/13] Docs/admin-guide/mm/damon/usage: document dests directory
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
` (4 preceding siblings ...)
2025-07-02 20:13 ` [RFC PATCH v3 05/13] Docs/ABI/damon: document schemes dests directory Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 07/13] mm/damon/core: Commit damos->target_nid/migrate_dests Bijan Tabatabai
` (7 subsequent siblings)
13 siblings, 0 replies; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr
From: SeongJae Park <sj@kernel.org>
Document the newly added DAMOS action destination directory of the DAMON
sysfs interface on the usage document.
Signed-off-by: SeongJae Park <sj@kernel.org>
---
Documentation/admin-guide/mm/damon/usage.rst | 33 +++++++++++++++++---
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/Documentation/admin-guide/mm/damon/usage.rst b/Documentation/admin-guide/mm/damon/usage.rst
index d960aba72b82..fc5c962353ed 100644
--- a/Documentation/admin-guide/mm/damon/usage.rst
+++ b/Documentation/admin-guide/mm/damon/usage.rst
@@ -85,6 +85,8 @@ comma (",").
│ │ │ │ │ │ │ :ref:`watermarks <sysfs_watermarks>`/metric,interval_us,high,mid,low
│ │ │ │ │ │ │ :ref:`{core_,ops_,}filters <sysfs_filters>`/nr_filters
│ │ │ │ │ │ │ │ 0/type,matching,allow,memcg_path,addr_start,addr_end,target_idx,min,max
+ │ │ │ │ │ │ │ :ref:`dests <damon_sysfs_dests>`/nr_dests
+ │ │ │ │ │ │ │ │ 0/id,weight
│ │ │ │ │ │ │ :ref:`stats <sysfs_schemes_stats>`/nr_tried,sz_tried,nr_applied,sz_applied,sz_ops_filter_passed,qt_exceeds
│ │ │ │ │ │ │ :ref:`tried_regions <sysfs_schemes_tried_regions>`/total_bytes
│ │ │ │ │ │ │ │ 0/start,end,nr_accesses,age,sz_filter_passed
@@ -307,10 +309,10 @@ to ``N-1``. Each directory represents each DAMON-based operation scheme.
schemes/<N>/
------------
-In each scheme directory, seven directories (``access_pattern``, ``quotas``,
-``watermarks``, ``core_filters``, ``ops_filters``, ``filters``, ``stats``, and
-``tried_regions``) and three files (``action``, ``target_nid`` and
-``apply_interval``) exist.
+In each scheme directory, eight directories (``access_pattern``, ``quotas``,
+``watermarks``, ``core_filters``, ``ops_filters``, ``filters``, ``dests``,
+``stats``, and ``tried_regions``) and three files (``action``, ``target_nid``
+and ``apply_interval``) exist.
The ``action`` file is for setting and getting the scheme's :ref:`action
<damon_design_damos_action>`. The keywords that can be written to and read
@@ -484,6 +486,29 @@ Refer to the :ref:`DAMOS filters design documentation
of different ``allow`` works, when each of the filters are supported, and
differences on stats.
+.. _damon_sysfs_dests:
+
+schemes/<N>/dests/
+------------------
+
+Directory for specifying the destinations of given DAMON-based operation
+scheme's action. This directory is ignored if the action of the given scheme
+is not supporting multiple destinations. Only ``DAMOS_MIGRATE_{HOT,COLD}``
+actions are supporting multiple destinations.
+
+In the beginning, the directory has only one file, ``nr_dests``. Writing a
+number (``N``) to the file creates the number of child directories named ``0``
+to ``N-1``. Each directory represents each action destination.
+
+Each destination directory contains two files, namely ``id`` and ``weight``.
+Users can write and read the identifier of the destination to ``id`` file.
+For ``DAMOS_MIGRATE_{HOT,COLD}`` actions, the migrate destination node's node
+id should be written to ``id`` file. Users can write and read the weight of
+the destination among the given destinations to the ``weight`` file. The
+weight can be an arbitrary integer. When DAMOS apply the action to each entity
+of the memory region, it will select the destination of the action based on the
+relative weights of the destinations.
+
.. _sysfs_schemes_stats:
schemes/<N>/stats/
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 07/13] mm/damon/core: Commit damos->target_nid/migrate_dests
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
` (5 preceding siblings ...)
2025-07-02 20:13 ` [RFC PATCH v3 06/13] Docs/admin-guide/mm/damon/usage: document " Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-02 21:03 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 08/13] mm/damon: Move migration helpers from paddr to ops-common Bijan Tabatabai
` (6 subsequent siblings)
13 siblings, 1 reply; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr
From: Bijan Tabatabai <bijantabatab@micron.com>
When committing new scheme parameters from the sysfs, copy the
target_nid and migrate_dests of the source schemes into the destination
schemes.
Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
---
mm/damon/core.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/mm/damon/core.c b/mm/damon/core.c
index a4c3cfe531df..0565aae8d1fa 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -943,6 +943,41 @@ static void damos_set_filters_default_reject(struct damos *s)
damos_filters_default_reject(&s->ops_filters);
}
+static int damos_commit_dests(struct damos *dst, struct damos *src)
+{
+ struct damos_migrate_dests *dst_dests, *src_dests;
+
+ dst_dests = &dst->migrate_dests;
+ src_dests = &src->migrate_dests;
+
+ if (dst_dests->nr_dests != src_dests->nr_dests) {
+ kfree(dst_dests->node_id_arr);
+ kfree(dst_dests->weight_arr);
+
+ dst_dests->node_id_arr = kmalloc_array(src_dests->nr_dests,
+ sizeof(*dst_dests->node_id_arr), GFP_KERNEL);
+ if (!dst_dests->node_id_arr) {
+ dst_dests->weight_arr = NULL;
+ return -ENOMEM;
+ }
+
+ dst_dests->weight_arr = kmalloc_array(src_dests->nr_dests,
+ sizeof(*dst_dests->weight_arr), GFP_KERNEL);
+ if (!dst_dests->weight_arr) {
+ /* ->node_id_arr will be freed by scheme destruction */
+ return -ENOMEM;
+ }
+ }
+
+ dst_dests->nr_dests = src_dests->nr_dests;
+ for (int i = 0; i < src_dests->nr_dests; i++) {
+ dst_dests->node_id_arr[i] = src_dests->node_id_arr[i];
+ dst_dests->weight_arr[i] = src_dests->weight_arr[i];
+ }
+
+ return 0;
+}
+
static int damos_commit_filters(struct damos *dst, struct damos *src)
{
int err;
@@ -983,6 +1018,11 @@ static int damos_commit(struct damos *dst, struct damos *src)
dst->wmarks = src->wmarks;
+ dst->target_nid = src->target_nid;
+ err = damos_commit_dests(dst, src);
+ if (err)
+ return err;
+
err = damos_commit_filters(dst, src);
return err;
}
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 08/13] mm/damon: Move migration helpers from paddr to ops-common
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
` (6 preceding siblings ...)
2025-07-02 20:13 ` [RFC PATCH v3 07/13] mm/damon/core: Commit damos->target_nid/migrate_dests Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-02 21:12 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 09/13] mm/damon/vaddr: Add vaddr versions of migrate_{hot,cold} Bijan Tabatabai
` (5 subsequent siblings)
13 siblings, 1 reply; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
From: Bijan Tabatabai <bijantabatab@micron.com>
This patch moves the damon_pa_migrate_pages function along with its
corresponding helper functions from paddr to ops-common. The function
prefix of "damon_pa_" was also changed to just "damon_" accordingly.
This patch will allow page migration to be available to vaddr schemes as
well as paddr schemes.
Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
---
mm/damon/ops-common.c | 120 +++++++++++++++++++++++++++++++++++++++++
mm/damon/ops-common.h | 2 +
mm/damon/paddr.c | 122 +-----------------------------------------
3 files changed, 123 insertions(+), 121 deletions(-)
diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
index b43620fee6bb..918158ef3d99 100644
--- a/mm/damon/ops-common.c
+++ b/mm/damon/ops-common.c
@@ -5,6 +5,7 @@
* Author: SeongJae Park <sj@kernel.org>
*/
+#include <linux/migrate.h>
#include <linux/mmu_notifier.h>
#include <linux/page_idle.h>
#include <linux/pagemap.h>
@@ -12,6 +13,7 @@
#include <linux/swap.h>
#include <linux/swapops.h>
+#include "../internal.h"
#include "ops-common.h"
/*
@@ -138,3 +140,121 @@ int damon_cold_score(struct damon_ctx *c, struct damon_region *r,
/* Return coldness of the region */
return DAMOS_MAX_SCORE - hotness;
}
+
+static unsigned int __damon_migrate_folio_list(
+ struct list_head *migrate_folios, struct pglist_data *pgdat,
+ int target_nid)
+{
+ unsigned int nr_succeeded = 0;
+ struct migration_target_control mtc = {
+ /*
+ * Allocate from 'node', or fail quickly and quietly.
+ * When this happens, 'page' will likely just be discarded
+ * instead of migrated.
+ */
+ .gfp_mask = (GFP_HIGHUSER_MOVABLE & ~__GFP_RECLAIM) |
+ __GFP_NOWARN | __GFP_NOMEMALLOC | GFP_NOWAIT,
+ .nid = target_nid,
+ };
+
+ if (pgdat->node_id == target_nid || target_nid == NUMA_NO_NODE)
+ return 0;
+
+ if (list_empty(migrate_folios))
+ return 0;
+
+ /* Migration ignores all cpuset and mempolicy settings */
+ migrate_pages(migrate_folios, alloc_migration_target, NULL,
+ (unsigned long)&mtc, MIGRATE_ASYNC, MR_DAMON,
+ &nr_succeeded);
+
+ return nr_succeeded;
+}
+
+static unsigned int damon_migrate_folio_list(struct list_head *folio_list,
+ struct pglist_data *pgdat,
+ int target_nid)
+{
+ unsigned int nr_migrated = 0;
+ struct folio *folio;
+ LIST_HEAD(ret_folios);
+ LIST_HEAD(migrate_folios);
+
+ while (!list_empty(folio_list)) {
+ struct folio *folio;
+
+ cond_resched();
+
+ folio = lru_to_folio(folio_list);
+ list_del(&folio->lru);
+
+ if (!folio_trylock(folio))
+ goto keep;
+
+ /* Relocate its contents to another node. */
+ list_add(&folio->lru, &migrate_folios);
+ folio_unlock(folio);
+ continue;
+keep:
+ list_add(&folio->lru, &ret_folios);
+ }
+ /* 'folio_list' is always empty here */
+
+ /* Migrate folios selected for migration */
+ nr_migrated += __damon_migrate_folio_list(
+ &migrate_folios, pgdat, target_nid);
+ /*
+ * Folios that could not be migrated are still in @migrate_folios. Add
+ * those back on @folio_list
+ */
+ if (!list_empty(&migrate_folios))
+ list_splice_init(&migrate_folios, folio_list);
+
+ try_to_unmap_flush();
+
+ list_splice(&ret_folios, folio_list);
+
+ while (!list_empty(folio_list)) {
+ folio = lru_to_folio(folio_list);
+ list_del(&folio->lru);
+ folio_putback_lru(folio);
+ }
+
+ return nr_migrated;
+}
+
+unsigned long damon_migrate_pages(struct list_head *folio_list, int target_nid)
+{
+ int nid;
+ unsigned long nr_migrated = 0;
+ LIST_HEAD(node_folio_list);
+ unsigned int noreclaim_flag;
+
+ if (list_empty(folio_list))
+ return nr_migrated;
+
+ noreclaim_flag = memalloc_noreclaim_save();
+
+ nid = folio_nid(lru_to_folio(folio_list));
+ do {
+ struct folio *folio = lru_to_folio(folio_list);
+
+ if (nid == folio_nid(folio)) {
+ list_move(&folio->lru, &node_folio_list);
+ continue;
+ }
+
+ nr_migrated += damon_migrate_folio_list(&node_folio_list,
+ NODE_DATA(nid),
+ target_nid);
+ nid = folio_nid(lru_to_folio(folio_list));
+ } while (!list_empty(folio_list));
+
+ nr_migrated += damon_migrate_folio_list(&node_folio_list,
+ NODE_DATA(nid),
+ target_nid);
+
+ memalloc_noreclaim_restore(noreclaim_flag);
+
+ return nr_migrated;
+}
diff --git a/mm/damon/ops-common.h b/mm/damon/ops-common.h
index cc9f5da9c012..54209a7e70e6 100644
--- a/mm/damon/ops-common.h
+++ b/mm/damon/ops-common.h
@@ -16,3 +16,5 @@ int damon_cold_score(struct damon_ctx *c, struct damon_region *r,
struct damos *s);
int damon_hot_score(struct damon_ctx *c, struct damon_region *r,
struct damos *s);
+
+unsigned long damon_migrate_pages(struct list_head *folio_list, int target_nid);
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
index fcab148e6865..48e3e6fed636 100644
--- a/mm/damon/paddr.c
+++ b/mm/damon/paddr.c
@@ -13,7 +13,6 @@
#include <linux/rmap.h>
#include <linux/swap.h>
#include <linux/memory-tiers.h>
-#include <linux/migrate.h>
#include <linux/mm_inline.h>
#include "../internal.h"
@@ -381,125 +380,6 @@ static unsigned long damon_pa_deactivate_pages(struct damon_region *r,
sz_filter_passed);
}
-static unsigned int __damon_pa_migrate_folio_list(
- struct list_head *migrate_folios, struct pglist_data *pgdat,
- int target_nid)
-{
- unsigned int nr_succeeded = 0;
- struct migration_target_control mtc = {
- /*
- * Allocate from 'node', or fail quickly and quietly.
- * When this happens, 'page' will likely just be discarded
- * instead of migrated.
- */
- .gfp_mask = (GFP_HIGHUSER_MOVABLE & ~__GFP_RECLAIM) |
- __GFP_NOWARN | __GFP_NOMEMALLOC | GFP_NOWAIT,
- .nid = target_nid,
- };
-
- if (pgdat->node_id == target_nid || target_nid == NUMA_NO_NODE)
- return 0;
-
- if (list_empty(migrate_folios))
- return 0;
-
- /* Migration ignores all cpuset and mempolicy settings */
- migrate_pages(migrate_folios, alloc_migration_target, NULL,
- (unsigned long)&mtc, MIGRATE_ASYNC, MR_DAMON,
- &nr_succeeded);
-
- return nr_succeeded;
-}
-
-static unsigned int damon_pa_migrate_folio_list(struct list_head *folio_list,
- struct pglist_data *pgdat,
- int target_nid)
-{
- unsigned int nr_migrated = 0;
- struct folio *folio;
- LIST_HEAD(ret_folios);
- LIST_HEAD(migrate_folios);
-
- while (!list_empty(folio_list)) {
- struct folio *folio;
-
- cond_resched();
-
- folio = lru_to_folio(folio_list);
- list_del(&folio->lru);
-
- if (!folio_trylock(folio))
- goto keep;
-
- /* Relocate its contents to another node. */
- list_add(&folio->lru, &migrate_folios);
- folio_unlock(folio);
- continue;
-keep:
- list_add(&folio->lru, &ret_folios);
- }
- /* 'folio_list' is always empty here */
-
- /* Migrate folios selected for migration */
- nr_migrated += __damon_pa_migrate_folio_list(
- &migrate_folios, pgdat, target_nid);
- /*
- * Folios that could not be migrated are still in @migrate_folios. Add
- * those back on @folio_list
- */
- if (!list_empty(&migrate_folios))
- list_splice_init(&migrate_folios, folio_list);
-
- try_to_unmap_flush();
-
- list_splice(&ret_folios, folio_list);
-
- while (!list_empty(folio_list)) {
- folio = lru_to_folio(folio_list);
- list_del(&folio->lru);
- folio_putback_lru(folio);
- }
-
- return nr_migrated;
-}
-
-static unsigned long damon_pa_migrate_pages(struct list_head *folio_list,
- int target_nid)
-{
- int nid;
- unsigned long nr_migrated = 0;
- LIST_HEAD(node_folio_list);
- unsigned int noreclaim_flag;
-
- if (list_empty(folio_list))
- return nr_migrated;
-
- noreclaim_flag = memalloc_noreclaim_save();
-
- nid = folio_nid(lru_to_folio(folio_list));
- do {
- struct folio *folio = lru_to_folio(folio_list);
-
- if (nid == folio_nid(folio)) {
- list_move(&folio->lru, &node_folio_list);
- continue;
- }
-
- nr_migrated += damon_pa_migrate_folio_list(&node_folio_list,
- NODE_DATA(nid),
- target_nid);
- nid = folio_nid(lru_to_folio(folio_list));
- } while (!list_empty(folio_list));
-
- nr_migrated += damon_pa_migrate_folio_list(&node_folio_list,
- NODE_DATA(nid),
- target_nid);
-
- memalloc_noreclaim_restore(noreclaim_flag);
-
- return nr_migrated;
-}
-
static unsigned long damon_pa_migrate(struct damon_region *r, struct damos *s,
unsigned long *sz_filter_passed)
{
@@ -527,7 +407,7 @@ static unsigned long damon_pa_migrate(struct damon_region *r, struct damos *s,
addr += folio_size(folio);
folio_put(folio);
}
- applied = damon_pa_migrate_pages(&folio_list, s->target_nid);
+ applied = damon_migrate_pages(&folio_list, s->target_nid);
cond_resched();
s->last_applied = folio;
return applied * PAGE_SIZE;
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 09/13] mm/damon/vaddr: Add vaddr versions of migrate_{hot,cold}
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
` (7 preceding siblings ...)
2025-07-02 20:13 ` [RFC PATCH v3 08/13] mm/damon: Move migration helpers from paddr to ops-common Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-02 23:51 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 10/13] Docs/mm/damon/design: Document vaddr support for migrate_{hot,cold} Bijan Tabatabai
` (4 subsequent siblings)
13 siblings, 1 reply; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
From: Bijan Tabatabai <bijantabatab@micron.com>
migrate_{hot,cold} are paddr schemes that are used to migrate hot/cold
data to a specified node. However, these schemes are only available when
doing physical address monitoring. This patch adds an implementation for
them virtual address monitoring as well.
Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
---
mm/damon/vaddr.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
index 46554e49a478..5cdfdc47c5ff 100644
--- a/mm/damon/vaddr.c
+++ b/mm/damon/vaddr.c
@@ -15,6 +15,7 @@
#include <linux/pagewalk.h>
#include <linux/sched/mm.h>
+#include "../internal.h"
#include "ops-common.h"
#ifdef CONFIG_DAMON_VADDR_KUNIT_TEST
@@ -610,6 +611,65 @@ static unsigned int damon_va_check_accesses(struct damon_ctx *ctx)
return max_nr_accesses;
}
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,
+ unsigned long next, struct mm_walk *walk)
+{
+ struct list_head *migration_list = walk->private;
+ struct folio *folio;
+ spinlock_t *ptl;
+ pmd_t pmde;
+
+ ptl = pmd_lock(walk->mm, pmd);
+ pmde = pmdp_get(pmd);
+
+ if (!pmd_present(pmde) || !pmd_trans_huge(pmde))
+ goto unlock;
+
+ folio = damon_get_folio(pmd_pfn(pmde));
+ if (!folio)
+ goto unlock;
+
+ if (!folio_isolate_lru(folio))
+ goto put_folio;
+
+ list_add(&folio->lru, migration_list);
+
+put_folio:
+ folio_put(folio);
+unlock:
+ spin_unlock(ptl);
+ return 0;
+}
+#else
+#define damos_va_migrate_pmd_entry NULL
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+
+static int damos_va_migrate_pte_entry(pte_t *pte, unsigned long addr,
+ unsigned long enxt, struct mm_walk *walk)
+{
+ struct list_head *migration_list = walk->private;
+ struct folio *folio;
+ pte_t ptent;
+
+ ptent = ptep_get(pte);
+ if (pte_none(*pte) || !pte_present(*pte))
+ return 0;
+
+ folio = damon_get_folio(pte_pfn(ptent));
+ if (!folio)
+ return 0;
+
+ if (!folio_isolate_lru(folio))
+ goto out;
+
+ list_add(&folio->lru, migration_list);
+
+out:
+ folio_put(folio);
+ return 0;
+}
+
/*
* Functions for the target validity check and cleanup
*/
@@ -653,6 +713,41 @@ static unsigned long damos_madvise(struct damon_target *target,
}
#endif /* CONFIG_ADVISE_SYSCALLS */
+static unsigned long damos_va_migrate(struct damon_target *target,
+ struct damon_region *r, struct damos *s,
+ unsigned long *sz_filter_passed)
+{
+ LIST_HEAD(folio_list);
+ struct task_struct *task;
+ struct mm_struct *mm;
+ unsigned long applied = 0;
+ struct mm_walk_ops walk_ops = {
+ .pmd_entry = damos_va_migrate_pmd_entry,
+ .pte_entry = damos_va_migrate_pte_entry,
+ .walk_lock = PGWALK_RDLOCK,
+ };
+
+ task = damon_get_task_struct(target);
+ if (!task)
+ return 0;
+
+ mm = damon_get_mm(target);
+ if (!mm)
+ goto put_task;
+
+ mmap_read_lock(mm);
+ walk_page_range(mm, r->ar.start, r->ar.end, &walk_ops, &folio_list);
+ mmap_read_unlock(mm);
+ mmput(mm);
+
+ applied = damon_migrate_pages(&folio_list, s->target_nid);
+ cond_resched();
+
+put_task:
+ put_task_struct(task);
+ return applied * PAGE_SIZE;
+}
+
static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,
struct damon_target *t, struct damon_region *r,
struct damos *scheme, unsigned long *sz_filter_passed)
@@ -675,6 +770,9 @@ static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,
case DAMOS_NOHUGEPAGE:
madv_action = MADV_NOHUGEPAGE;
break;
+ case DAMOS_MIGRATE_HOT:
+ case DAMOS_MIGRATE_COLD:
+ return damos_va_migrate(t, r, scheme, sz_filter_passed);
case DAMOS_STAT:
return 0;
default:
@@ -695,6 +793,10 @@ static int damon_va_scheme_score(struct damon_ctx *context,
switch (scheme->action) {
case DAMOS_PAGEOUT:
return damon_cold_score(context, r, scheme);
+ case DAMOS_MIGRATE_HOT:
+ return damon_hot_score(context, r, scheme);
+ case DAMOS_MIGRATE_COLD:
+ return damon_cold_score(context, r, scheme);
default:
break;
}
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 10/13] Docs/mm/damon/design: Document vaddr support for migrate_{hot,cold}
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
` (8 preceding siblings ...)
2025-07-02 20:13 ` [RFC PATCH v3 09/13] mm/damon/vaddr: Add vaddr versions of migrate_{hot,cold} Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-02 23:52 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 11/13] mm/damon/vaddr: Use damos->migrate_dests in migrate_{hot,cold} Bijan Tabatabai
` (3 subsequent siblings)
13 siblings, 1 reply; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
From: Bijan Tabatabai <bijantabatab@micron.com>
Document that the migrate_{hot,cold} schemes can be used by the vaddr
operations set.
Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
---
Documentation/mm/damon/design.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/Documentation/mm/damon/design.rst b/Documentation/mm/damon/design.rst
index ddc50db3afa4..03f8137256f5 100644
--- a/Documentation/mm/damon/design.rst
+++ b/Documentation/mm/damon/design.rst
@@ -452,9 +452,9 @@ that supports each action are as below.
- ``lru_deprio``: Deprioritize the region on its LRU lists.
Supported by ``paddr`` operations set.
- ``migrate_hot``: Migrate the regions prioritizing warmer regions.
- Supported by ``paddr`` operations set.
+ Supported by ``vaddr``, ``fvaddr`` and ``paddr`` operations set.
- ``migrate_cold``: Migrate the regions prioritizing colder regions.
- Supported by ``paddr`` operations set.
+ Supported by ``vaddr``, ``fvaddr`` and ``paddr`` operations set.
- ``stat``: Do nothing but count the statistics.
Supported by all operations sets.
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 11/13] mm/damon/vaddr: Use damos->migrate_dests in migrate_{hot,cold}
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
` (9 preceding siblings ...)
2025-07-02 20:13 ` [RFC PATCH v3 10/13] Docs/mm/damon/design: Document vaddr support for migrate_{hot,cold} Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-03 0:32 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 12/13] mm/damon: Move folio filtering from paddr to ops-common Bijan Tabatabai
` (2 subsequent siblings)
13 siblings, 1 reply; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
From: Bijan Tabatabai <bijantabatab@micron.com>
damos->migrate_dests provides a list of nodes the migrate_{hot,cold}
actions should migrate to, as well as the weights which specify the
ratio pages should be migrated to each destination node.
This patch interleaves pages in the migrate_{hot,cold} actions according
to the information provided in damos->migrate_dests if it is used. The
interleaving algorithm used is similar to the one used in
weighted_interleave_nid(). If damos->migration_dests is not provided, the
actions migrate pages to the node specified in damos->target_nid as
before.
Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
---
mm/damon/vaddr.c | 114 ++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 97 insertions(+), 17 deletions(-)
diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
index 5cdfdc47c5ff..5f230a427fdc 100644
--- a/mm/damon/vaddr.c
+++ b/mm/damon/vaddr.c
@@ -611,11 +611,76 @@ static unsigned int damon_va_check_accesses(struct damon_ctx *ctx)
return max_nr_accesses;
}
+struct damos_va_migrate_private {
+ struct list_head *migration_lists;
+ struct damos *scheme;
+};
+
+/*
+ * Place the given folio in the migration_list corresponding to where the folio
+ * should be migrated.
+ *
+ * The algorithm used here is similar to weighted_interleave_nid()
+ */
+static void damos_va_migrate_folio(struct folio *folio,
+ struct vm_area_struct *vma, unsigned long addr,
+ struct damos_migrate_dests *dests,
+ struct list_head *migration_lists)
+{
+ pgoff_t ilx;
+ int order;
+ unsigned int target;
+ unsigned int weight_total = 0;
+ int i;
+
+ /*
+ * If dests is empty, there is only one migration list corresponding
+ * to s->target_nid.
+ */
+ if (!dests->nr_dests) {
+ i = 0;
+ goto isolate;
+ }
+
+ order = folio_order(folio);
+ ilx = vma->vm_pgoff >> order;
+ ilx += (addr - vma->vm_start) >> (PAGE_SHIFT + order);
+
+ for (i = 0; i < dests->nr_dests; i++)
+ weight_total += dests->weight_arr[i];
+
+ /* If the total weights are somehow 0, don't migrate at all */
+ if (!weight_total)
+ return;
+
+ target = ilx % weight_total;
+ for (i = 0; i < dests->nr_dests; i++) {
+ if (target < dests->weight_arr[i])
+ break;
+ target -= dests->weight_arr[i];
+ }
+
+ /* No index being chosen indicates a mistake in the algorithm */
+ if (i == dests->nr_dests) {
+ WARN_ONCE(1, "Error determining target interleave node");
+ return;
+ }
+
+isolate:
+ if (!folio_isolate_lru(folio))
+ return;
+
+ list_add(&folio->lru, &migration_lists[i]);
+}
+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,
unsigned long next, struct mm_walk *walk)
{
- struct list_head *migration_list = walk->private;
+ struct damos_va_migrate_private *priv = walk->private;
+ struct damos *s = priv->scheme;
+ struct list_head *migration_lists = priv->migration_lists;
+ struct damos_migrate_dests *dests = &s->migrate_dests;
struct folio *folio;
spinlock_t *ptl;
pmd_t pmde;
@@ -630,12 +695,8 @@ static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,
if (!folio)
goto unlock;
- if (!folio_isolate_lru(folio))
- goto put_folio;
-
- list_add(&folio->lru, migration_list);
+ damos_va_migrate_folio(folio, walk->vma, addr, dests, migration_lists);
-put_folio:
folio_put(folio);
unlock:
spin_unlock(ptl);
@@ -648,7 +709,10 @@ static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,
static int damos_va_migrate_pte_entry(pte_t *pte, unsigned long addr,
unsigned long enxt, struct mm_walk *walk)
{
- struct list_head *migration_list = walk->private;
+ struct damos_va_migrate_private *priv = walk->private;
+ struct damos *s = priv->scheme;
+ struct list_head *migration_lists = priv->migration_lists;
+ struct damos_migrate_dests *dests = &s->migrate_dests;
struct folio *folio;
pte_t ptent;
@@ -660,12 +724,8 @@ static int damos_va_migrate_pte_entry(pte_t *pte, unsigned long addr,
if (!folio)
return 0;
- if (!folio_isolate_lru(folio))
- goto out;
-
- list_add(&folio->lru, migration_list);
+ damos_va_migrate_folio(folio, walk->vma, addr, dests, migration_lists);
-out:
folio_put(folio);
return 0;
}
@@ -717,34 +777,54 @@ static unsigned long damos_va_migrate(struct damon_target *target,
struct damon_region *r, struct damos *s,
unsigned long *sz_filter_passed)
{
- LIST_HEAD(folio_list);
+ struct damos_va_migrate_private priv;
struct task_struct *task;
struct mm_struct *mm;
+ int nr_dests;
+ int nid;
+ bool use_target_nid;
unsigned long applied = 0;
+ struct damos_migrate_dests *dests = &s->migrate_dests;
struct mm_walk_ops walk_ops = {
.pmd_entry = damos_va_migrate_pmd_entry,
.pte_entry = damos_va_migrate_pte_entry,
.walk_lock = PGWALK_RDLOCK,
};
+ use_target_nid = dests->nr_dests == 0;
+ nr_dests = use_target_nid ? 1 : dests->nr_dests;
+ priv.scheme = s;
+ priv.migration_lists = kmalloc_array(nr_dests,
+ sizeof(struct list_head), GFP_KERNEL);
+ if (!priv.migration_lists)
+ return 0;
+
+ for (int i = 0; i < nr_dests; i++)
+ INIT_LIST_HEAD(&priv.migration_lists[i]);
+
task = damon_get_task_struct(target);
if (!task)
- return 0;
+ goto free_lists;
mm = damon_get_mm(target);
if (!mm)
goto put_task;
mmap_read_lock(mm);
- walk_page_range(mm, r->ar.start, r->ar.end, &walk_ops, &folio_list);
+ walk_page_range(mm, r->ar.start, r->ar.end, &walk_ops, &priv);
mmap_read_unlock(mm);
mmput(mm);
- applied = damon_migrate_pages(&folio_list, s->target_nid);
- cond_resched();
+ for (int i = 0; i < nr_dests; i++) {
+ nid = use_target_nid ? s->target_nid : dests->node_id_arr[i];
+ applied += damon_migrate_pages(&priv.migration_lists[i], nid);
+ cond_resched();
+ }
put_task:
put_task_struct(task);
+free_lists:
+ kfree(priv.migration_lists);
return applied * PAGE_SIZE;
}
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 12/13] mm/damon: Move folio filtering from paddr to ops-common
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
` (10 preceding siblings ...)
2025-07-02 20:13 ` [RFC PATCH v3 11/13] mm/damon/vaddr: Use damos->migrate_dests in migrate_{hot,cold} Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-03 0:34 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 13/13] mm/damon/vaddr: Apply filters in migrate_{hot/cold} Bijan Tabatabai
2025-07-03 1:03 ` [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions SeongJae Park
13 siblings, 1 reply; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
From: Bijan Tabatabai <bijantabatab@micron.com>
This patch moves damos_pa_filter_match and the functions it calls to
ops-common, renaming it to damos_folio_filter_match. Doing so allows us
to share the filtering logic for the vaddr version of the
migrate_{hot,cold} schemes.
Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
---
mm/damon/ops-common.c | 150 +++++++++++++++++++++++++++++++++++++++++
mm/damon/ops-common.h | 3 +
mm/damon/paddr.c | 153 +-----------------------------------------
3 files changed, 154 insertions(+), 152 deletions(-)
diff --git a/mm/damon/ops-common.c b/mm/damon/ops-common.c
index 918158ef3d99..6a9797d1d7ff 100644
--- a/mm/damon/ops-common.c
+++ b/mm/damon/ops-common.c
@@ -141,6 +141,156 @@ int damon_cold_score(struct damon_ctx *c, struct damon_region *r,
return DAMOS_MAX_SCORE - hotness;
}
+static bool damon_folio_mkold_one(struct folio *folio,
+ struct vm_area_struct *vma, unsigned long addr, void *arg)
+{
+ DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, addr, 0);
+
+ while (page_vma_mapped_walk(&pvmw)) {
+ addr = pvmw.address;
+ if (pvmw.pte)
+ damon_ptep_mkold(pvmw.pte, vma, addr);
+ else
+ damon_pmdp_mkold(pvmw.pmd, vma, addr);
+ }
+ return true;
+}
+
+void damon_folio_mkold(struct folio *folio)
+{
+ struct rmap_walk_control rwc = {
+ .rmap_one = damon_folio_mkold_one,
+ .anon_lock = folio_lock_anon_vma_read,
+ };
+ bool need_lock;
+
+ if (!folio_mapped(folio) || !folio_raw_mapping(folio)) {
+ folio_set_idle(folio);
+ return;
+ }
+
+ need_lock = !folio_test_anon(folio) || folio_test_ksm(folio);
+ if (need_lock && !folio_trylock(folio))
+ return;
+
+ rmap_walk(folio, &rwc);
+
+ if (need_lock)
+ folio_unlock(folio);
+
+}
+
+static bool damon_folio_young_one(struct folio *folio,
+ struct vm_area_struct *vma, unsigned long addr, void *arg)
+{
+ bool *accessed = arg;
+ DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, addr, 0);
+ pte_t pte;
+
+ *accessed = false;
+ while (page_vma_mapped_walk(&pvmw)) {
+ addr = pvmw.address;
+ if (pvmw.pte) {
+ pte = ptep_get(pvmw.pte);
+
+ /*
+ * PFN swap PTEs, such as device-exclusive ones, that
+ * actually map pages are "old" from a CPU perspective.
+ * The MMU notifier takes care of any device aspects.
+ */
+ *accessed = (pte_present(pte) && pte_young(pte)) ||
+ !folio_test_idle(folio) ||
+ mmu_notifier_test_young(vma->vm_mm, addr);
+ } else {
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+ *accessed = pmd_young(pmdp_get(pvmw.pmd)) ||
+ !folio_test_idle(folio) ||
+ mmu_notifier_test_young(vma->vm_mm, addr);
+#else
+ WARN_ON_ONCE(1);
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+ }
+ if (*accessed) {
+ page_vma_mapped_walk_done(&pvmw);
+ break;
+ }
+ }
+
+ /* If accessed, stop walking */
+ return *accessed == false;
+}
+
+bool damon_folio_young(struct folio *folio)
+{
+ bool accessed = false;
+ struct rmap_walk_control rwc = {
+ .arg = &accessed,
+ .rmap_one = damon_folio_young_one,
+ .anon_lock = folio_lock_anon_vma_read,
+ };
+ bool need_lock;
+
+ if (!folio_mapped(folio) || !folio_raw_mapping(folio)) {
+ if (folio_test_idle(folio))
+ return false;
+ else
+ return true;
+ }
+
+ need_lock = !folio_test_anon(folio) || folio_test_ksm(folio);
+ if (need_lock && !folio_trylock(folio))
+ return false;
+
+ rmap_walk(folio, &rwc);
+
+ if (need_lock)
+ folio_unlock(folio);
+
+ return accessed;
+}
+
+bool damos_folio_filter_match(struct damos_filter *filter, struct folio *folio)
+{
+ bool matched = false;
+ struct mem_cgroup *memcg;
+ size_t folio_sz;
+
+ switch (filter->type) {
+ case DAMOS_FILTER_TYPE_ANON:
+ matched = folio_test_anon(folio);
+ break;
+ case DAMOS_FILTER_TYPE_ACTIVE:
+ matched = folio_test_active(folio);
+ break;
+ case DAMOS_FILTER_TYPE_MEMCG:
+ rcu_read_lock();
+ memcg = folio_memcg_check(folio);
+ if (!memcg)
+ matched = false;
+ else
+ matched = filter->memcg_id == mem_cgroup_id(memcg);
+ rcu_read_unlock();
+ break;
+ case DAMOS_FILTER_TYPE_YOUNG:
+ matched = damon_folio_young(folio);
+ if (matched)
+ damon_folio_mkold(folio);
+ break;
+ case DAMOS_FILTER_TYPE_HUGEPAGE_SIZE:
+ folio_sz = folio_size(folio);
+ matched = filter->sz_range.min <= folio_sz &&
+ folio_sz <= filter->sz_range.max;
+ break;
+ case DAMOS_FILTER_TYPE_UNMAPPED:
+ matched = !folio_mapped(folio) || !folio_raw_mapping(folio);
+ break;
+ default:
+ break;
+ }
+
+ return matched == filter->matching;
+}
+
static unsigned int __damon_migrate_folio_list(
struct list_head *migrate_folios, struct pglist_data *pgdat,
int target_nid)
diff --git a/mm/damon/ops-common.h b/mm/damon/ops-common.h
index 54209a7e70e6..61ad54aaf256 100644
--- a/mm/damon/ops-common.h
+++ b/mm/damon/ops-common.h
@@ -11,10 +11,13 @@ struct folio *damon_get_folio(unsigned long pfn);
void damon_ptep_mkold(pte_t *pte, struct vm_area_struct *vma, unsigned long addr);
void damon_pmdp_mkold(pmd_t *pmd, struct vm_area_struct *vma, unsigned long addr);
+void damon_folio_mkold(struct folio *folio);
+bool damon_folio_young(struct folio *folio);
int damon_cold_score(struct damon_ctx *c, struct damon_region *r,
struct damos *s);
int damon_hot_score(struct damon_ctx *c, struct damon_region *r,
struct damos *s);
+bool damos_folio_filter_match(struct damos_filter *filter, struct folio *folio);
unsigned long damon_migrate_pages(struct list_head *folio_list, int target_nid);
diff --git a/mm/damon/paddr.c b/mm/damon/paddr.c
index 48e3e6fed636..53a55c5114fb 100644
--- a/mm/damon/paddr.c
+++ b/mm/damon/paddr.c
@@ -18,45 +18,6 @@
#include "../internal.h"
#include "ops-common.h"
-static bool damon_folio_mkold_one(struct folio *folio,
- struct vm_area_struct *vma, unsigned long addr, void *arg)
-{
- DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, addr, 0);
-
- while (page_vma_mapped_walk(&pvmw)) {
- addr = pvmw.address;
- if (pvmw.pte)
- damon_ptep_mkold(pvmw.pte, vma, addr);
- else
- damon_pmdp_mkold(pvmw.pmd, vma, addr);
- }
- return true;
-}
-
-static void damon_folio_mkold(struct folio *folio)
-{
- struct rmap_walk_control rwc = {
- .rmap_one = damon_folio_mkold_one,
- .anon_lock = folio_lock_anon_vma_read,
- };
- bool need_lock;
-
- if (!folio_mapped(folio) || !folio_raw_mapping(folio)) {
- folio_set_idle(folio);
- return;
- }
-
- need_lock = !folio_test_anon(folio) || folio_test_ksm(folio);
- if (need_lock && !folio_trylock(folio))
- return;
-
- rmap_walk(folio, &rwc);
-
- if (need_lock)
- folio_unlock(folio);
-
-}
-
static void damon_pa_mkold(unsigned long paddr)
{
struct folio *folio = damon_get_folio(PHYS_PFN(paddr));
@@ -86,75 +47,6 @@ static void damon_pa_prepare_access_checks(struct damon_ctx *ctx)
}
}
-static bool damon_folio_young_one(struct folio *folio,
- struct vm_area_struct *vma, unsigned long addr, void *arg)
-{
- bool *accessed = arg;
- DEFINE_FOLIO_VMA_WALK(pvmw, folio, vma, addr, 0);
- pte_t pte;
-
- *accessed = false;
- while (page_vma_mapped_walk(&pvmw)) {
- addr = pvmw.address;
- if (pvmw.pte) {
- pte = ptep_get(pvmw.pte);
-
- /*
- * PFN swap PTEs, such as device-exclusive ones, that
- * actually map pages are "old" from a CPU perspective.
- * The MMU notifier takes care of any device aspects.
- */
- *accessed = (pte_present(pte) && pte_young(pte)) ||
- !folio_test_idle(folio) ||
- mmu_notifier_test_young(vma->vm_mm, addr);
- } else {
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
- *accessed = pmd_young(pmdp_get(pvmw.pmd)) ||
- !folio_test_idle(folio) ||
- mmu_notifier_test_young(vma->vm_mm, addr);
-#else
- WARN_ON_ONCE(1);
-#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
- }
- if (*accessed) {
- page_vma_mapped_walk_done(&pvmw);
- break;
- }
- }
-
- /* If accessed, stop walking */
- return *accessed == false;
-}
-
-static bool damon_folio_young(struct folio *folio)
-{
- bool accessed = false;
- struct rmap_walk_control rwc = {
- .arg = &accessed,
- .rmap_one = damon_folio_young_one,
- .anon_lock = folio_lock_anon_vma_read,
- };
- bool need_lock;
-
- if (!folio_mapped(folio) || !folio_raw_mapping(folio)) {
- if (folio_test_idle(folio))
- return false;
- else
- return true;
- }
-
- need_lock = !folio_test_anon(folio) || folio_test_ksm(folio);
- if (need_lock && !folio_trylock(folio))
- return false;
-
- rmap_walk(folio, &rwc);
-
- if (need_lock)
- folio_unlock(folio);
-
- return accessed;
-}
-
static bool damon_pa_young(unsigned long paddr, unsigned long *folio_sz)
{
struct folio *folio = damon_get_folio(PHYS_PFN(paddr));
@@ -205,49 +97,6 @@ static unsigned int damon_pa_check_accesses(struct damon_ctx *ctx)
return max_nr_accesses;
}
-static bool damos_pa_filter_match(struct damos_filter *filter,
- struct folio *folio)
-{
- bool matched = false;
- struct mem_cgroup *memcg;
- size_t folio_sz;
-
- switch (filter->type) {
- case DAMOS_FILTER_TYPE_ANON:
- matched = folio_test_anon(folio);
- break;
- case DAMOS_FILTER_TYPE_ACTIVE:
- matched = folio_test_active(folio);
- break;
- case DAMOS_FILTER_TYPE_MEMCG:
- rcu_read_lock();
- memcg = folio_memcg_check(folio);
- if (!memcg)
- matched = false;
- else
- matched = filter->memcg_id == mem_cgroup_id(memcg);
- rcu_read_unlock();
- break;
- case DAMOS_FILTER_TYPE_YOUNG:
- matched = damon_folio_young(folio);
- if (matched)
- damon_folio_mkold(folio);
- break;
- case DAMOS_FILTER_TYPE_HUGEPAGE_SIZE:
- folio_sz = folio_size(folio);
- matched = filter->sz_range.min <= folio_sz &&
- folio_sz <= filter->sz_range.max;
- break;
- case DAMOS_FILTER_TYPE_UNMAPPED:
- matched = !folio_mapped(folio) || !folio_raw_mapping(folio);
- break;
- default:
- break;
- }
-
- return matched == filter->matching;
-}
-
/*
* damos_pa_filter_out - Return true if the page should be filtered out.
*/
@@ -259,7 +108,7 @@ static bool damos_pa_filter_out(struct damos *scheme, struct folio *folio)
return false;
damos_for_each_ops_filter(filter, scheme) {
- if (damos_pa_filter_match(filter, folio))
+ if (damos_folio_filter_match(filter, folio))
return !filter->allow;
}
return scheme->ops_filters_default_reject;
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* [RFC PATCH v3 13/13] mm/damon/vaddr: Apply filters in migrate_{hot/cold}
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
` (11 preceding siblings ...)
2025-07-02 20:13 ` [RFC PATCH v3 12/13] mm/damon: Move folio filtering from paddr to ops-common Bijan Tabatabai
@ 2025-07-02 20:13 ` Bijan Tabatabai
2025-07-03 0:51 ` SeongJae Park
2025-07-03 1:03 ` [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions SeongJae Park
13 siblings, 1 reply; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-02 20:13 UTC (permalink / raw)
To: damon, linux-mm, linux-kernel, linux-doc
Cc: sj, akpm, corbet, joshua.hahnjy, bijantabatab, venkataravis,
emirakhur, ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
From: Bijan Tabatabai <bijantabatab@micron.com>
The paddr versions of migrate_{hot/cold} filter out folios from
migration based on the scheme's filters. This patch does the same for
the vaddr versions of those schemes.
The filtering code is mostly the same for the paddr and vaddr versions.
The exception is the young filter. paddr determines if a page is young
by doing a folio rmap walk to find the page table entries corresponding
to the folio. However, vaddr schemes have easier access to the page
tables, so we add some logic to avoid the extra work.
Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
---
mm/damon/vaddr.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
index 5f230a427fdc..2a485bf19101 100644
--- a/mm/damon/vaddr.c
+++ b/mm/damon/vaddr.c
@@ -611,6 +611,62 @@ static unsigned int damon_va_check_accesses(struct damon_ctx *ctx)
return max_nr_accesses;
}
+static bool damos_va_filter_young(struct damos_filter *filter,
+ struct folio *folio, struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep, pmd_t *pmdp)
+{
+ bool young;
+
+ if (ptep) {
+ young = pte_young(*ptep);
+ } else if (pmdp) {
+ young = pmd_young(*pmdp);
+ } else {
+ WARN_ONCE(1, "Neither ptep nor pmdp provided");
+ return false;
+ }
+
+ young = young || !folio_test_idle(folio) ||
+ mmu_notifier_test_young(vma->vm_mm, addr);
+
+ if (young && ptep)
+ damon_ptep_mkold(ptep, vma, addr);
+ else if (young && pmdp)
+ damon_pmdp_mkold(pmdp, vma, addr);
+
+ return young == filter->matching;
+}
+
+static bool damos_va_filter_out(struct damos *scheme, struct folio *folio,
+ struct vm_area_struct *vma, unsigned long addr,
+ pte_t *ptep, pmd_t *pmdp)
+{
+ struct damos_filter *filter;
+ bool matched;
+
+ if (scheme->core_filters_allowed)
+ return false;
+
+ damos_for_each_ops_filter(filter, scheme) {
+ /*
+ * damos_folio_filter_match checks the young filter by doing an
+ * rmap on the folio to find its page table. However, being the
+ * vaddr scheme, we have direct access to the page tables, so
+ * use that instead.
+ */
+ if (filter->type == DAMOS_FILTER_TYPE_YOUNG) {
+ matched = damos_va_filter_young(filter, folio, vma,
+ addr, ptep, pmdp);
+ } else {
+ matched = damos_folio_filter_match(filter, folio);
+ }
+
+ if (matched)
+ return !filter->allow;
+ }
+ return scheme->ops_filters_default_reject;
+}
+
struct damos_va_migrate_private {
struct list_head *migration_lists;
struct damos *scheme;
@@ -695,8 +751,12 @@ static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,
if (!folio)
goto unlock;
+ if (damos_va_filter_out(s, folio, walk->vma, addr, NULL, pmd))
+ goto put_folio;
+
damos_va_migrate_folio(folio, walk->vma, addr, dests, migration_lists);
+put_folio:
folio_put(folio);
unlock:
spin_unlock(ptl);
@@ -724,8 +784,12 @@ static int damos_va_migrate_pte_entry(pte_t *pte, unsigned long addr,
if (!folio)
return 0;
+ if (damos_va_filter_out(s, folio, walk->vma, addr, pte, NULL))
+ goto put_folio;
+
damos_va_migrate_folio(folio, walk->vma, addr, dests, migration_lists);
+put_folio:
folio_put(folio);
return 0;
}
--
2.43.5
^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [RFC PATCH v3 07/13] mm/damon/core: Commit damos->target_nid/migrate_dests
2025-07-02 20:13 ` [RFC PATCH v3 07/13] mm/damon/core: Commit damos->target_nid/migrate_dests Bijan Tabatabai
@ 2025-07-02 21:03 ` SeongJae Park
2025-07-08 14:04 ` Bijan Tabatabai
0 siblings, 1 reply; 25+ messages in thread
From: SeongJae Park @ 2025-07-02 21:03 UTC (permalink / raw)
To: Bijan Tabatabai
Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, joshua.hahnjy, bijantabatab, venkataravis, emirakhur,
ajayjoshi, vtavarespetr
On Wed, 2 Jul 2025 15:13:30 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
> From: Bijan Tabatabai <bijantabatab@micron.com>
>
> When committing new scheme parameters from the sysfs, copy the
> target_nid and migrate_dests of the source schemes into the destination
> schemes.
Fixing the missed update of target_nid deserves Fixes: and Cc: stable@ in my
opinion. Could you please split and post the part as another patch? For the
Fixes, I think 83dc7bbaecae ("mm/damon/sysfs: use damon_commit_ctx()") should
be appripriate.
>
> Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
Assuming my above request is accepted,
Reviewed-by: SeongJae Park <sj@kernel.org>
> ---
> mm/damon/core.c | 40 ++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 40 insertions(+)
>
> diff --git a/mm/damon/core.c b/mm/damon/core.c
> index a4c3cfe531df..0565aae8d1fa 100644
> --- a/mm/damon/core.c
> +++ b/mm/damon/core.c
> @@ -943,6 +943,41 @@ static void damos_set_filters_default_reject(struct damos *s)
> damos_filters_default_reject(&s->ops_filters);
> }
>
> +static int damos_commit_dests(struct damos *dst, struct damos *src)
> +{
> + struct damos_migrate_dests *dst_dests, *src_dests;
> +
> + dst_dests = &dst->migrate_dests;
> + src_dests = &src->migrate_dests;
> +
> + if (dst_dests->nr_dests != src_dests->nr_dests) {
> + kfree(dst_dests->node_id_arr);
> + kfree(dst_dests->weight_arr);
> +
> + dst_dests->node_id_arr = kmalloc_array(src_dests->nr_dests,
> + sizeof(*dst_dests->node_id_arr), GFP_KERNEL);
> + if (!dst_dests->node_id_arr) {
> + dst_dests->weight_arr = NULL;
> + return -ENOMEM;
> + }
> +
> + dst_dests->weight_arr = kmalloc_array(src_dests->nr_dests,
> + sizeof(*dst_dests->weight_arr), GFP_KERNEL);
> + if (!dst_dests->weight_arr) {
> + /* ->node_id_arr will be freed by scheme destruction */
> + return -ENOMEM;
> + }
> + }
> +
> + dst_dests->nr_dests = src_dests->nr_dests;
> + for (int i = 0; i < src_dests->nr_dests; i++) {
> + dst_dests->node_id_arr[i] = src_dests->node_id_arr[i];
> + dst_dests->weight_arr[i] = src_dests->weight_arr[i];
> + }
> +
> + return 0;
> +}
> +
> static int damos_commit_filters(struct damos *dst, struct damos *src)
> {
> int err;
> @@ -983,6 +1018,11 @@ static int damos_commit(struct damos *dst, struct damos *src)
>
> dst->wmarks = src->wmarks;
>
> + dst->target_nid = src->target_nid;
> + err = damos_commit_dests(dst, src);
> + if (err)
> + return err;
> +
As mentioned above, let's split and post this part as another individual patch.
> err = damos_commit_filters(dst, src);
> return err;
> }
> --
> 2.43.5
Thanks,
SJ
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFC PATCH v3 08/13] mm/damon: Move migration helpers from paddr to ops-common
2025-07-02 20:13 ` [RFC PATCH v3 08/13] mm/damon: Move migration helpers from paddr to ops-common Bijan Tabatabai
@ 2025-07-02 21:12 ` SeongJae Park
0 siblings, 0 replies; 25+ messages in thread
From: SeongJae Park @ 2025-07-02 21:12 UTC (permalink / raw)
To: Bijan Tabatabai
Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, joshua.hahnjy, bijantabatab, venkataravis, emirakhur,
ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
On Wed, 2 Jul 2025 15:13:31 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
> From: Bijan Tabatabai <bijantabatab@micron.com>
>
> This patch moves the damon_pa_migrate_pages function along with its
> corresponding helper functions from paddr to ops-common. The function
> prefix of "damon_pa_" was also changed to just "damon_" accordingly.
>
> This patch will allow page migration to be available to vaddr schemes as
> well as paddr schemes.
Looks good to me!
>
> Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
Reviewed-by: SeongJae Park <sj@kernel.org>
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFC PATCH v3 09/13] mm/damon/vaddr: Add vaddr versions of migrate_{hot,cold}
2025-07-02 20:13 ` [RFC PATCH v3 09/13] mm/damon/vaddr: Add vaddr versions of migrate_{hot,cold} Bijan Tabatabai
@ 2025-07-02 23:51 ` SeongJae Park
2025-07-03 0:10 ` SeongJae Park
0 siblings, 1 reply; 25+ messages in thread
From: SeongJae Park @ 2025-07-02 23:51 UTC (permalink / raw)
To: Bijan Tabatabai
Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, joshua.hahnjy, bijantabatab, venkataravis, emirakhur,
ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
On Wed, 2 Jul 2025 15:13:32 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
> From: Bijan Tabatabai <bijantabatab@micron.com>
>
> migrate_{hot,cold} are paddr schemes that are used to migrate hot/cold
> data to a specified node. However, these schemes are only available when
> doing physical address monitoring. This patch adds an implementation for
> them virtual address monitoring as well.
>
> Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
> ---
> mm/damon/vaddr.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 102 insertions(+)
>
> diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
> index 46554e49a478..5cdfdc47c5ff 100644
> --- a/mm/damon/vaddr.c
> +++ b/mm/damon/vaddr.c
> @@ -15,6 +15,7 @@
> #include <linux/pagewalk.h>
> #include <linux/sched/mm.h>
>
> +#include "../internal.h"
> #include "ops-common.h"
>
> #ifdef CONFIG_DAMON_VADDR_KUNIT_TEST
> @@ -610,6 +611,65 @@ static unsigned int damon_va_check_accesses(struct damon_ctx *ctx)
> return max_nr_accesses;
> }
>
> +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> +static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,
> + unsigned long next, struct mm_walk *walk)
I'd suggest to put CONFIG_TRANSPARENT_HUGEPAGE check into the body of this
function and handle both pmd and pte here, consistent to
damon_young_pmd_entry().
> +{
> + struct list_head *migration_list = walk->private;
> + struct folio *folio;
> + spinlock_t *ptl;
> + pmd_t pmde;
> +
> + ptl = pmd_lock(walk->mm, pmd);
> + pmde = pmdp_get(pmd);
> +
> + if (!pmd_present(pmde) || !pmd_trans_huge(pmde))
> + goto unlock;
> +
> + folio = damon_get_folio(pmd_pfn(pmde));
> + if (!folio)
> + goto unlock;
> +
> + if (!folio_isolate_lru(folio))
> + goto put_folio;
> +
> + list_add(&folio->lru, migration_list);
> +
> +put_folio:
> + folio_put(folio);
> +unlock:
> + spin_unlock(ptl);
> + return 0;
> +}
> +#else
> +#define damos_va_migrate_pmd_entry NULL
> +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
> +
> +static int damos_va_migrate_pte_entry(pte_t *pte, unsigned long addr,
> + unsigned long enxt, struct mm_walk *walk)
Nit. s/enxt/next/ ?
> +{
> + struct list_head *migration_list = walk->private;
> + struct folio *folio;
> + pte_t ptent;
> +
> + ptent = ptep_get(pte);
> + if (pte_none(*pte) || !pte_present(*pte))
> + return 0;
Shouldn't we use cached pte value (ptent) instad of *pte? I'd suggest merging
this into damos_va_migrate_pmd_entry() consistent to damon_young_pmd_entry().
> +
> + folio = damon_get_folio(pte_pfn(ptent));
> + if (!folio)
> + return 0;
> +
> + if (!folio_isolate_lru(folio))
> + goto out;
> +
> + list_add(&folio->lru, migration_list);
> +
> +out:
> + folio_put(folio);
> + return 0;
> +}
> +
> /*
> * Functions for the target validity check and cleanup
> */
> @@ -653,6 +713,41 @@ static unsigned long damos_madvise(struct damon_target *target,
> }
> #endif /* CONFIG_ADVISE_SYSCALLS */
>
> +static unsigned long damos_va_migrate(struct damon_target *target,
> + struct damon_region *r, struct damos *s,
> + unsigned long *sz_filter_passed)
> +{
> + LIST_HEAD(folio_list);
> + struct task_struct *task;
> + struct mm_struct *mm;
> + unsigned long applied = 0;
> + struct mm_walk_ops walk_ops = {
> + .pmd_entry = damos_va_migrate_pmd_entry,
> + .pte_entry = damos_va_migrate_pte_entry,
> + .walk_lock = PGWALK_RDLOCK,
> + };
> +
> + task = damon_get_task_struct(target);
> + if (!task)
> + return 0;
> +
> + mm = damon_get_mm(target);
> + if (!mm)
> + goto put_task;
> +
> + mmap_read_lock(mm);
> + walk_page_range(mm, r->ar.start, r->ar.end, &walk_ops, &folio_list);
> + mmap_read_unlock(mm);
> + mmput(mm);
> +
> + applied = damon_migrate_pages(&folio_list, s->target_nid);
> + cond_resched();
> +
> +put_task:
> + put_task_struct(task);
Seems task is not being used in real, so this variable and the related code in
this function can be removed? Or, am I missing something?
> + return applied * PAGE_SIZE;
> +}
> +
> static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,
> struct damon_target *t, struct damon_region *r,
> struct damos *scheme, unsigned long *sz_filter_passed)
> @@ -675,6 +770,9 @@ static unsigned long damon_va_apply_scheme(struct damon_ctx *ctx,
> case DAMOS_NOHUGEPAGE:
> madv_action = MADV_NOHUGEPAGE;
> break;
> + case DAMOS_MIGRATE_HOT:
> + case DAMOS_MIGRATE_COLD:
> + return damos_va_migrate(t, r, scheme, sz_filter_passed);
> case DAMOS_STAT:
> return 0;
> default:
> @@ -695,6 +793,10 @@ static int damon_va_scheme_score(struct damon_ctx *context,
> switch (scheme->action) {
> case DAMOS_PAGEOUT:
> return damon_cold_score(context, r, scheme);
> + case DAMOS_MIGRATE_HOT:
> + return damon_hot_score(context, r, scheme);
> + case DAMOS_MIGRATE_COLD:
> + return damon_cold_score(context, r, scheme);
> default:
> break;
> }
> --
> 2.43.5
Thanks,
SJ
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFC PATCH v3 10/13] Docs/mm/damon/design: Document vaddr support for migrate_{hot,cold}
2025-07-02 20:13 ` [RFC PATCH v3 10/13] Docs/mm/damon/design: Document vaddr support for migrate_{hot,cold} Bijan Tabatabai
@ 2025-07-02 23:52 ` SeongJae Park
0 siblings, 0 replies; 25+ messages in thread
From: SeongJae Park @ 2025-07-02 23:52 UTC (permalink / raw)
To: Bijan Tabatabai
Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, joshua.hahnjy, bijantabatab, venkataravis, emirakhur,
ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
On Wed, 2 Jul 2025 15:13:33 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
> From: Bijan Tabatabai <bijantabatab@micron.com>
>
> Document that the migrate_{hot,cold} schemes can be used by the vaddr
> operations set.
>
> Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
Reviewed-by: SeongJae Park <sj@kernel.org>
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFC PATCH v3 09/13] mm/damon/vaddr: Add vaddr versions of migrate_{hot,cold}
2025-07-02 23:51 ` SeongJae Park
@ 2025-07-03 0:10 ` SeongJae Park
0 siblings, 0 replies; 25+ messages in thread
From: SeongJae Park @ 2025-07-03 0:10 UTC (permalink / raw)
To: SeongJae Park
Cc: Bijan Tabatabai, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, joshua.hahnjy, bijantabatab, venkataravis, emirakhur,
ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
On Wed, 2 Jul 2025 16:51:38 -0700 SeongJae Park <sj@kernel.org> wrote:
> On Wed, 2 Jul 2025 15:13:32 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
>
> > From: Bijan Tabatabai <bijantabatab@micron.com>
> >
> > migrate_{hot,cold} are paddr schemes that are used to migrate hot/cold
> > data to a specified node. However, these schemes are only available when
> > doing physical address monitoring. This patch adds an implementation for
> > them virtual address monitoring as well.
> >
> > Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> > Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> > Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
> > ---
> > mm/damon/vaddr.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 102 insertions(+)
> >
> > diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
> > index 46554e49a478..5cdfdc47c5ff 100644
> > --- a/mm/damon/vaddr.c
> > +++ b/mm/damon/vaddr.c
> > @@ -15,6 +15,7 @@
> > #include <linux/pagewalk.h>
> > #include <linux/sched/mm.h>
> >
> > +#include "../internal.h"
> > #include "ops-common.h"
> >
> > #ifdef CONFIG_DAMON_VADDR_KUNIT_TEST
> > @@ -610,6 +611,65 @@ static unsigned int damon_va_check_accesses(struct damon_ctx *ctx)
> > return max_nr_accesses;
> > }
> >
> > +#ifdef CONFIG_TRANSPARENT_HUGEPAGE
> > +static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,
> > + unsigned long next, struct mm_walk *walk)
>
> I'd suggest to put CONFIG_TRANSPARENT_HUGEPAGE check into the body of this
> function and handle both pmd and pte here, consistent to
> damon_young_pmd_entry().
Ah, unlike damon_young_pmd_entry() which is for a single address, this is for
walking the range of a given DAMON region, and hence should have a separate pte
entry function. Please ignore the above comment.
[...]
> > +static int damos_va_migrate_pte_entry(pte_t *pte, unsigned long addr,
> > + unsigned long enxt, struct mm_walk *walk)
>
> Nit. s/enxt/next/ ?
>
> > +{
> > + struct list_head *migration_list = walk->private;
> > + struct folio *folio;
> > + pte_t ptent;
> > +
> > + ptent = ptep_get(pte);
> > + if (pte_none(*pte) || !pte_present(*pte))
> > + return 0;
>
> Shouldn't we use cached pte value (ptent) instad of *pte? I'd suggest merging
> this into damos_va_migrate_pmd_entry() consistent to damon_young_pmd_entry().
Again, I overlooked the fact that this is for walking not only single address
point but a range. Please ignore the latter suggestion.
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFC PATCH v3 11/13] mm/damon/vaddr: Use damos->migrate_dests in migrate_{hot,cold}
2025-07-02 20:13 ` [RFC PATCH v3 11/13] mm/damon/vaddr: Use damos->migrate_dests in migrate_{hot,cold} Bijan Tabatabai
@ 2025-07-03 0:32 ` SeongJae Park
0 siblings, 0 replies; 25+ messages in thread
From: SeongJae Park @ 2025-07-03 0:32 UTC (permalink / raw)
To: Bijan Tabatabai
Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, joshua.hahnjy, bijantabatab, venkataravis, emirakhur,
ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
On Wed, 2 Jul 2025 15:13:34 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
> From: Bijan Tabatabai <bijantabatab@micron.com>
>
> damos->migrate_dests provides a list of nodes the migrate_{hot,cold}
> actions should migrate to, as well as the weights which specify the
> ratio pages should be migrated to each destination node.
>
> This patch interleaves pages in the migrate_{hot,cold} actions according
> to the information provided in damos->migrate_dests if it is used. The
> interleaving algorithm used is similar to the one used in
> weighted_interleave_nid(). If damos->migration_dests is not provided, the
> actions migrate pages to the node specified in damos->target_nid as
> before.
>
> Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
> ---
> mm/damon/vaddr.c | 114 ++++++++++++++++++++++++++++++++++++++++-------
> 1 file changed, 97 insertions(+), 17 deletions(-)
>
> diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
> index 5cdfdc47c5ff..5f230a427fdc 100644
> --- a/mm/damon/vaddr.c
> +++ b/mm/damon/vaddr.c
> @@ -611,11 +611,76 @@ static unsigned int damon_va_check_accesses(struct damon_ctx *ctx)
> return max_nr_accesses;
> }
>
> +struct damos_va_migrate_private {
> + struct list_head *migration_lists;
> + struct damos *scheme;
> +};
> +
> +/*
> + * Place the given folio in the migration_list corresponding to where the folio
> + * should be migrated.
> + *
> + * The algorithm used here is similar to weighted_interleave_nid()
> + */
> +static void damos_va_migrate_folio(struct folio *folio,
> + struct vm_area_struct *vma, unsigned long addr,
> + struct damos_migrate_dests *dests,
> + struct list_head *migration_lists)
Based on the name, I was thinking the function may do the real migration.
What about using more self-introductory name, say,
damos_va_migrate_dests_add()?
> +{
> + pgoff_t ilx;
> + int order;
> + unsigned int target;
> + unsigned int weight_total = 0;
> + int i;
> +
> + /*
> + * If dests is empty, there is only one migration list corresponding
> + * to s->target_nid.
> + */
> + if (!dests->nr_dests) {
> + i = 0;
> + goto isolate;
> + }
> +
> + order = folio_order(folio);
> + ilx = vma->vm_pgoff >> order;
> + ilx += (addr - vma->vm_start) >> (PAGE_SHIFT + order);
> +
> + for (i = 0; i < dests->nr_dests; i++)
> + weight_total += dests->weight_arr[i];
> +
> + /* If the total weights are somehow 0, don't migrate at all */
> + if (!weight_total)
> + return;
> +
> + target = ilx % weight_total;
> + for (i = 0; i < dests->nr_dests; i++) {
> + if (target < dests->weight_arr[i])
> + break;
> + target -= dests->weight_arr[i];
> + }
> +
> + /* No index being chosen indicates a mistake in the algorithm */
> + if (i == dests->nr_dests) {
> + WARN_ONCE(1, "Error determining target interleave node");
> + return;
> + }
This cannot happen, right? Let's just remove this.
> +
> +isolate:
> + if (!folio_isolate_lru(folio))
> + return;
> +
> + list_add(&folio->lru, &migration_lists[i]);
> +}
> +
> #ifdef CONFIG_TRANSPARENT_HUGEPAGE
> static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,
> unsigned long next, struct mm_walk *walk)
> {
> - struct list_head *migration_list = walk->private;
> + struct damos_va_migrate_private *priv = walk->private;
> + struct damos *s = priv->scheme;
> + struct list_head *migration_lists = priv->migration_lists;
> + struct damos_migrate_dests *dests = &s->migrate_dests;
Seems priv->sheme is only a carrier of ->migrate_dests. Why don't you add that
in damos_va_migrate_private directly?
> struct folio *folio;
> spinlock_t *ptl;
> pmd_t pmde;
> @@ -630,12 +695,8 @@ static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,
> if (!folio)
> goto unlock;
>
> - if (!folio_isolate_lru(folio))
> - goto put_folio;
> -
> - list_add(&folio->lru, migration_list);
> + damos_va_migrate_folio(folio, walk->vma, addr, dests, migration_lists);
>
> -put_folio:
> folio_put(folio);
> unlock:
> spin_unlock(ptl);
> @@ -648,7 +709,10 @@ static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,
> static int damos_va_migrate_pte_entry(pte_t *pte, unsigned long addr,
> unsigned long enxt, struct mm_walk *walk)
> {
> - struct list_head *migration_list = walk->private;
> + struct damos_va_migrate_private *priv = walk->private;
> + struct damos *s = priv->scheme;
> + struct list_head *migration_lists = priv->migration_lists;
> + struct damos_migrate_dests *dests = &s->migrate_dests;
> struct folio *folio;
> pte_t ptent;
>
> @@ -660,12 +724,8 @@ static int damos_va_migrate_pte_entry(pte_t *pte, unsigned long addr,
> if (!folio)
> return 0;
>
> - if (!folio_isolate_lru(folio))
> - goto out;
> -
> - list_add(&folio->lru, migration_list);
> + damos_va_migrate_folio(folio, walk->vma, addr, dests, migration_lists);
>
> -out:
> folio_put(folio);
> return 0;
> }
> @@ -717,34 +777,54 @@ static unsigned long damos_va_migrate(struct damon_target *target,
> struct damon_region *r, struct damos *s,
> unsigned long *sz_filter_passed)
> {
> - LIST_HEAD(folio_list);
> + struct damos_va_migrate_private priv;
> struct task_struct *task;
> struct mm_struct *mm;
> + int nr_dests;
> + int nid;
> + bool use_target_nid;
> unsigned long applied = 0;
> + struct damos_migrate_dests *dests = &s->migrate_dests;
> struct mm_walk_ops walk_ops = {
> .pmd_entry = damos_va_migrate_pmd_entry,
> .pte_entry = damos_va_migrate_pte_entry,
> .walk_lock = PGWALK_RDLOCK,
> };
>
> + use_target_nid = dests->nr_dests == 0;
> + nr_dests = use_target_nid ? 1 : dests->nr_dests;
> + priv.scheme = s;
> + priv.migration_lists = kmalloc_array(nr_dests,
> + sizeof(struct list_head), GFP_KERNEL);
sizeof(*priv.migration_lists)?
> + if (!priv.migration_lists)
> + return 0;
> +
> + for (int i = 0; i < nr_dests; i++)
> + INIT_LIST_HEAD(&priv.migration_lists[i]);
> +
> task = damon_get_task_struct(target);
> if (!task)
> - return 0;
> + goto free_lists;
>
> mm = damon_get_mm(target);
> if (!mm)
> goto put_task;
>
> mmap_read_lock(mm);
> - walk_page_range(mm, r->ar.start, r->ar.end, &walk_ops, &folio_list);
> + walk_page_range(mm, r->ar.start, r->ar.end, &walk_ops, &priv);
> mmap_read_unlock(mm);
> mmput(mm);
>
> - applied = damon_migrate_pages(&folio_list, s->target_nid);
> - cond_resched();
> + for (int i = 0; i < nr_dests; i++) {
> + nid = use_target_nid ? s->target_nid : dests->node_id_arr[i];
> + applied += damon_migrate_pages(&priv.migration_lists[i], nid);
> + cond_resched();
> + }
>
> put_task:
> put_task_struct(task);
> +free_lists:
> + kfree(priv.migration_lists);
> return applied * PAGE_SIZE;
> }
>
> --
> 2.43.5
>
>
Thanks,
SJ
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFC PATCH v3 12/13] mm/damon: Move folio filtering from paddr to ops-common
2025-07-02 20:13 ` [RFC PATCH v3 12/13] mm/damon: Move folio filtering from paddr to ops-common Bijan Tabatabai
@ 2025-07-03 0:34 ` SeongJae Park
0 siblings, 0 replies; 25+ messages in thread
From: SeongJae Park @ 2025-07-03 0:34 UTC (permalink / raw)
To: Bijan Tabatabai
Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, joshua.hahnjy, bijantabatab, venkataravis, emirakhur,
ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
On Wed, 2 Jul 2025 15:13:35 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
> From: Bijan Tabatabai <bijantabatab@micron.com>
>
> This patch moves damos_pa_filter_match and the functions it calls to
> ops-common, renaming it to damos_folio_filter_match. Doing so allows us
> to share the filtering logic for the vaddr version of the
> migrate_{hot,cold} schemes.
Nice catch!
>
> Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
Reviewed-by: SeongJae Park <sj@kernel.org>
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFC PATCH v3 13/13] mm/damon/vaddr: Apply filters in migrate_{hot/cold}
2025-07-02 20:13 ` [RFC PATCH v3 13/13] mm/damon/vaddr: Apply filters in migrate_{hot/cold} Bijan Tabatabai
@ 2025-07-03 0:51 ` SeongJae Park
0 siblings, 0 replies; 25+ messages in thread
From: SeongJae Park @ 2025-07-03 0:51 UTC (permalink / raw)
To: Bijan Tabatabai
Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, joshua.hahnjy, bijantabatab, venkataravis, emirakhur,
ajayjoshi, vtavarespetr, Ravi Shankar Jonnalagadda
On Wed, 2 Jul 2025 15:13:36 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
> From: Bijan Tabatabai <bijantabatab@micron.com>
>
> The paddr versions of migrate_{hot/cold} filter out folios from
> migration based on the scheme's filters. This patch does the same for
> the vaddr versions of those schemes.
>
> The filtering code is mostly the same for the paddr and vaddr versions.
> The exception is the young filter. paddr determines if a page is young
> by doing a folio rmap walk to find the page table entries corresponding
> to the folio. However, vaddr schemes have easier access to the page
> tables, so we add some logic to avoid the extra work.
>
> Co-developed-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Ravi Shankar Jonnalagadda <ravis.opensrc@micron.com>
> Signed-off-by: Bijan Tabatabai <bijantabatab@micron.com>
> ---
> mm/damon/vaddr.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 64 insertions(+)
>
> diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
> index 5f230a427fdc..2a485bf19101 100644
> --- a/mm/damon/vaddr.c
> +++ b/mm/damon/vaddr.c
> @@ -611,6 +611,62 @@ static unsigned int damon_va_check_accesses(struct damon_ctx *ctx)
> return max_nr_accesses;
> }
>
> +static bool damos_va_filter_young(struct damos_filter *filter,
> + struct folio *folio, struct vm_area_struct *vma,
> + unsigned long addr, pte_t *ptep, pmd_t *pmdp)
> +{
> + bool young;
> +
> + if (ptep) {
> + young = pte_young(*ptep);
Let's use ptep_get().
> + } else if (pmdp) {
> + young = pmd_young(*pmdp);
Let's use pmdp_get().
> + } else {
> + WARN_ONCE(1, "Neither ptep nor pmdp provided");
> + return false;
> + }
Can this really happen? If so, let's remove WARN_ONCE(). If not, let's drop
the entire else case.
> +
> + young = young || !folio_test_idle(folio) ||
> + mmu_notifier_test_young(vma->vm_mm, addr);
> +
> + if (young && ptep)
> + damon_ptep_mkold(ptep, vma, addr);
> + else if (young && pmdp)
> + damon_pmdp_mkold(pmdp, vma, addr);
> +
> + return young == filter->matching;
I now realize this function is not returning if the folio is young, but if the
youngness matches the filter. Let's rename, say,
damos_va_filter_young_match()?
> +}
> +
> +static bool damos_va_filter_out(struct damos *scheme, struct folio *folio,
> + struct vm_area_struct *vma, unsigned long addr,
> + pte_t *ptep, pmd_t *pmdp)
> +{
> + struct damos_filter *filter;
> + bool matched;
> +
> + if (scheme->core_filters_allowed)
> + return false;
> +
> + damos_for_each_ops_filter(filter, scheme) {
> + /*
> + * damos_folio_filter_match checks the young filter by doing an
> + * rmap on the folio to find its page table. However, being the
> + * vaddr scheme, we have direct access to the page tables, so
> + * use that instead.
> + */
> + if (filter->type == DAMOS_FILTER_TYPE_YOUNG) {
> + matched = damos_va_filter_young(filter, folio, vma,
> + addr, ptep, pmdp);
> + } else {
> + matched = damos_folio_filter_match(filter, folio);
> + }
Let's drop enclosing braces for single line if-esle statements.
> +
> + if (matched)
> + return !filter->allow;
> + }
> + return scheme->ops_filters_default_reject;
> +}
> +
> struct damos_va_migrate_private {
> struct list_head *migration_lists;
> struct damos *scheme;
> @@ -695,8 +751,12 @@ static int damos_va_migrate_pmd_entry(pmd_t *pmd, unsigned long addr,
> if (!folio)
> goto unlock;
>
> + if (damos_va_filter_out(s, folio, walk->vma, addr, NULL, pmd))
> + goto put_folio;
> +
> damos_va_migrate_folio(folio, walk->vma, addr, dests, migration_lists);
>
> +put_folio:
> folio_put(folio);
> unlock:
> spin_unlock(ptl);
> @@ -724,8 +784,12 @@ static int damos_va_migrate_pte_entry(pte_t *pte, unsigned long addr,
> if (!folio)
> return 0;
>
> + if (damos_va_filter_out(s, folio, walk->vma, addr, pte, NULL))
> + goto put_folio;
> +
> damos_va_migrate_folio(folio, walk->vma, addr, dests, migration_lists);
>
> +put_folio:
> folio_put(folio);
> return 0;
> }
> --
> 2.43.5
>
>
Thanks,
SJ
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
` (12 preceding siblings ...)
2025-07-02 20:13 ` [RFC PATCH v3 13/13] mm/damon/vaddr: Apply filters in migrate_{hot/cold} Bijan Tabatabai
@ 2025-07-03 1:03 ` SeongJae Park
13 siblings, 0 replies; 25+ messages in thread
From: SeongJae Park @ 2025-07-03 1:03 UTC (permalink / raw)
To: Bijan Tabatabai
Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, joshua.hahnjy, bijantabatab, venkataravis, emirakhur,
ajayjoshi, vtavarespetr
Hello Bijan,
On Wed, 2 Jul 2025 15:13:23 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
> From: Bijan Tabatabai <bijantabatab@micron.com>
>
> A recent patch set automatically sets the interleave weight for each node
> according to the node's maximum bandwidth [1]. In another thread, the patch
> set's author, Joshua Hahn, wondered if/how thes weights should be changed
> if the bandwidth utilization of the system changes [2].
>
> This patch set adds the mechanism for dynamically changing how application
> data is interleaved across nodes while leaving the policy of what the
> interleave weights should be to userspace. It does this by having the
> migrate_{hot,cold} operating schemes interleave application data according
> to the list of migration nodes and weights passed in via the DAMON sysfs
> interface. This functionality can be used to dynamically adjust how folios
> are interleaved by having a userspace process adjust those weights. If no
> specific destination nodes or weights are provided, the migrate_{hot,cold}
> actions will only migrate folios to damos->target_nid as before.
[...]
> Functionality Test
> ==================
> Below is an example of this new functionality in use to confirm that these
> patches behave as intended.
> In this example, the user starts an application, alloc_data, which
> allocates 1GB using the default memory policy (i.e. allocate to local
> memory) then sleeps. Afterwards, we start DAMON to interleave the data at a
> 1:1 ratio. Using numastat, we show that DAMON has migrated the
> application's data to match the new interleave ratio.
> For this example, I modified the userspace damo tool [8] to write to the
> migration_dest sysfs files. I plan to upstream these changes when these
> patches are merged.
Looking forward to!
[...]
> Performance Test
> ================
[...]
> Updating the interleave weights and having DAMON migrate the workload data
> according to the weights resulted in an approximarely 25% speedup.
Nice!
[...]
> Revision History
> ================
> Changes from v2 [9]:
> - Implement interleaving using vaddr instead of paddr
> - Add vaddr implementation of migrate_{hot,cold}
> - Use DAMON specific interleave weights instead of mempolicy weights
Appreciate your efforts on revisioning!
I left a few comments including simple change requests and questions as replies
to each patch. In high level, looks good to me.
[...]
> P.S., I will be out of office Thursday until next week Tuesday, so please
> forgive any delayed responses.
No worry, please take your time and fun! :)
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFC PATCH v3 07/13] mm/damon/core: Commit damos->target_nid/migrate_dests
2025-07-02 21:03 ` SeongJae Park
@ 2025-07-08 14:04 ` Bijan Tabatabai
2025-07-08 17:32 ` SeongJae Park
0 siblings, 1 reply; 25+ messages in thread
From: Bijan Tabatabai @ 2025-07-08 14:04 UTC (permalink / raw)
To: SeongJae Park
Cc: damon, linux-mm, linux-kernel, linux-doc, akpm, corbet,
joshua.hahnjy, bijantabatab, venkataravis, emirakhur, ajayjoshi,
vtavarespetr
On Wed, Jul 2, 2025 at 4:03 PM SeongJae Park <sj@kernel.org> wrote:
>
> On Wed, 2 Jul 2025 15:13:30 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
>
> > From: Bijan Tabatabai <bijantabatab@micron.com>
> >
> > When committing new scheme parameters from the sysfs, copy the
> > target_nid and migrate_dests of the source schemes into the destination
> > schemes.
>
> Fixing the missed update of target_nid deserves Fixes: and Cc: stable@ in my
> opinion. Could you please split and post the part as another patch? For the
> Fixes, I think 83dc7bbaecae ("mm/damon/sysfs: use damon_commit_ctx()") should
> be appripriate.
Hi SJ,
To clarify, would you prefer it to be a seperate patch within the next
version of this patchset? Or would you prefer it to be sent separately
from the next version of the patchset?
Thanks,
Bijan
[...]
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFC PATCH v3 07/13] mm/damon/core: Commit damos->target_nid/migrate_dests
2025-07-08 14:04 ` Bijan Tabatabai
@ 2025-07-08 17:32 ` SeongJae Park
0 siblings, 0 replies; 25+ messages in thread
From: SeongJae Park @ 2025-07-08 17:32 UTC (permalink / raw)
To: Bijan Tabatabai
Cc: SeongJae Park, damon, linux-mm, linux-kernel, linux-doc, akpm,
corbet, joshua.hahnjy, bijantabatab, venkataravis, emirakhur,
ajayjoshi, vtavarespetr
Hi Bijan,
On Tue, 8 Jul 2025 09:04:02 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
> On Wed, Jul 2, 2025 at 4:03 PM SeongJae Park <sj@kernel.org> wrote:
> >
> > On Wed, 2 Jul 2025 15:13:30 -0500 Bijan Tabatabai <bijan311@gmail.com> wrote:
> >
> > > From: Bijan Tabatabai <bijantabatab@micron.com>
> > >
> > > When committing new scheme parameters from the sysfs, copy the
> > > target_nid and migrate_dests of the source schemes into the destination
> > > schemes.
> >
> > Fixing the missed update of target_nid deserves Fixes: and Cc: stable@ in my
> > opinion. Could you please split and post the part as another patch? For the
> > Fixes, I think 83dc7bbaecae ("mm/damon/sysfs: use damon_commit_ctx()") should
> > be appripriate.
>
> Hi SJ,
>
> To clarify, would you prefer it to be a seperate patch within the next
> version of this patchset? Or would you prefer it to be sent separately
> from the next version of the patchset?
I'd prefer latter (separate one).
Sorry for making the point ambiguous, and giving me this chance to clarify :)
Thanks,
SJ
[...]
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2025-07-08 17:32 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-02 20:13 [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 01/13] mm/damon: add struct damos_migrate_dests Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 02/13] mm/damon/core: add damos->migrate_dests field Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 03/13] mm/damon/sysfs-schemes: implement DAMOS action destinations directory Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 04/13] mm/damon/sysfs-schemes: set damos->migrate_dests Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 05/13] Docs/ABI/damon: document schemes dests directory Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 06/13] Docs/admin-guide/mm/damon/usage: document " Bijan Tabatabai
2025-07-02 20:13 ` [RFC PATCH v3 07/13] mm/damon/core: Commit damos->target_nid/migrate_dests Bijan Tabatabai
2025-07-02 21:03 ` SeongJae Park
2025-07-08 14:04 ` Bijan Tabatabai
2025-07-08 17:32 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 08/13] mm/damon: Move migration helpers from paddr to ops-common Bijan Tabatabai
2025-07-02 21:12 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 09/13] mm/damon/vaddr: Add vaddr versions of migrate_{hot,cold} Bijan Tabatabai
2025-07-02 23:51 ` SeongJae Park
2025-07-03 0:10 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 10/13] Docs/mm/damon/design: Document vaddr support for migrate_{hot,cold} Bijan Tabatabai
2025-07-02 23:52 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 11/13] mm/damon/vaddr: Use damos->migrate_dests in migrate_{hot,cold} Bijan Tabatabai
2025-07-03 0:32 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 12/13] mm/damon: Move folio filtering from paddr to ops-common Bijan Tabatabai
2025-07-03 0:34 ` SeongJae Park
2025-07-02 20:13 ` [RFC PATCH v3 13/13] mm/damon/vaddr: Apply filters in migrate_{hot/cold} Bijan Tabatabai
2025-07-03 0:51 ` SeongJae Park
2025-07-03 1:03 ` [RFC PATCH v3 00/13] mm/damon/vaddr: Allow interleaving in migrate_{hot,cold} actions SeongJae Park
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).