From: Akinobu Mita <akinobu.mita@gmail.com>
To: damon@lists.linux.dev
Cc: linux-perf-users@vger.kernel.org, sj@kernel.org, akinobu.mita@gmail.com
Subject: [RFC PATCH v3 1/4] mm/damon/core: add code borrowed from report-based monitoring work
Date: Thu, 23 Apr 2026 09:42:07 +0900 [thread overview]
Message-ID: <20260423004211.7037-2-akinobu.mita@gmail.com> (raw)
In-Reply-To: <20260423004211.7037-1-akinobu.mita@gmail.com>
The perf event-based monitoring will be implemented on top of the
report-based monitoring infrastructure, but since the migration is
still in progress, only borrow the following necessary code for now.
* struct damon_access_report
* access_reported field in struct damon_region
* sample/primitives/ sysfs directory
[1] https://lore.kernel.org/linux-mm/20251208062943.68824-6-sj@kernel.org/T/
---
include/linux/damon.h | 68 ++++++
mm/damon/core.c | 1 +
mm/damon/sysfs.c | 499 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 568 insertions(+)
diff --git a/include/linux/damon.h b/include/linux/damon.h
index f2cdb7c3f5e6..9ba26d8a0bce 100644
--- a/include/linux/damon.h
+++ b/include/linux/damon.h
@@ -85,6 +85,7 @@ struct damon_region {
unsigned int age;
/* private: Internal value for age calculation. */
unsigned int last_nr_accesses;
+ bool access_reported;
};
/**
@@ -112,6 +113,30 @@ struct damon_target {
bool obsolete;
};
+/**
+ * struct damon_access_report - Represent single access report information.
+ * @paddr: Start physical address of the accessed address range.
+ * @vaddr: Start virtual address of the accessed address range.
+ * @size: The size of the accessed address range.
+ * @cpu: The id of the CPU that made the access.
+ * @tid: The task id of the task that made the access.
+ * @is_write: Whether the access is write.
+ *
+ * Any DAMON API callers that notified access events can report the information
+ * to DAMON using damon_report_access(). This struct contains the reporting
+ * information. Refer to damon_report_access() for more details.
+ */
+struct damon_access_report {
+ unsigned long paddr;
+ unsigned long vaddr;
+ unsigned long size;
+ unsigned int cpu;
+ pid_t tid;
+ bool is_write;
+/* private: */
+ unsigned long report_jiffies; /* when this report is made */
+};
+
/**
* enum damos_action - Represents an action of a Data Access Monitoring-based
* Operation Scheme.
@@ -763,6 +788,49 @@ struct damon_attrs {
unsigned long aggr_samples;
};
+/**
+ * enum damon_sample_filter_type - Type of &struct damon_sample_filter.
+ *
+ * @DAMON_FILTER_TYPE_CPUMASK: Filter by access-generated CPUs.
+ * @DAMON_FILTER_TYPE_THREADS: Filter by access-generated threads.
+ * @DAMON_FILTER_TYPE_WRITE: Filter by whether the access was for writing.
+ *
+ * Read &struct damon_sample_control for more details.
+ */
+enum damon_sample_filter_type {
+ DAMON_FILTER_TYPE_CPUMASK,
+ DAMON_FILTER_TYPE_THREADS,
+ DAMON_FILTER_TYPE_WRITE,
+};
+
+/**
+ * struct damon_sample_filter - &struct damon_access_report filter.
+ *
+ * @type: The type of this filter.
+ * @matching: Whether it is for condition-matching reports.
+ * @allow: Whether to include or excludie the @matching reports.
+ * @cpumask: Access-generated CPUs if @type is DAMON_FILTER_TYPE_CPUMASK.
+ * @tid_arr: Array of access-generated thread ids, if @type is
+ * DAMON_FILTER_TYPE_THREADS.
+ * @nr_tids: Size of @tid_arr, if @type is DAMON_FILTER_TYPE_THREADS.
+ * @list: List head for siblings.
+ *
+ * Read &struct damon_sample_control for more details.
+ */
+struct damon_sample_filter {
+ enum damon_sample_filter_type type;
+ bool matching;
+ bool allow;
+ union {
+ cpumask_t cpumask;
+ struct {
+ pid_t *tid_arr;
+ int nr_tids;
+ };
+ };
+ struct list_head list;
+};
+
/**
* struct damon_ctx - Represents a context for each monitoring. This is the
* main interface that allows users to set the attributes and get the results
diff --git a/mm/damon/core.c b/mm/damon/core.c
index 3dbbbfdeff71..a52b2962aa22 100644
--- a/mm/damon/core.c
+++ b/mm/damon/core.c
@@ -142,6 +142,7 @@ struct damon_region *damon_new_region(unsigned long start, unsigned long end)
region->age = 0;
region->last_nr_accesses = 0;
+ region->access_reported = false;
return region;
}
diff --git a/mm/damon/sysfs.c b/mm/damon/sysfs.c
index eefa959aa30a..c19556f2af3b 100644
--- a/mm/damon/sysfs.c
+++ b/mm/damon/sysfs.c
@@ -747,6 +747,483 @@ static const struct kobj_type damon_sysfs_intervals_ktype = {
.default_groups = damon_sysfs_intervals_groups,
};
+/*
+ * access check report filter directory
+ */
+
+struct damon_sysfs_sample_filter {
+ struct kobject kobj;
+ enum damon_sample_filter_type type;
+ bool matching;
+ bool allow;
+ cpumask_t cpumask;
+};
+
+static struct damon_sysfs_sample_filter *damon_sysfs_sample_filter_alloc(void)
+{
+ return kzalloc(sizeof(struct damon_sysfs_sample_filter), GFP_KERNEL);
+}
+
+struct damon_sysfs_sample_filter_type_name {
+ enum damon_sample_filter_type type;
+ char *name;
+};
+
+static const struct damon_sysfs_sample_filter_type_name
+damon_sysfs_sample_filter_type_names[] = {
+ {
+ .type = DAMON_FILTER_TYPE_CPUMASK,
+ .name = "cpumask",
+ },
+};
+
+static ssize_t type_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_sample_filter *filter = container_of(kobj,
+ struct damon_sysfs_sample_filter, kobj);
+ int i = 0;
+
+ for (; i < ARRAY_SIZE(damon_sysfs_sample_filter_type_names); i++) {
+ const struct damon_sysfs_sample_filter_type_name *type_name;
+
+ type_name = &damon_sysfs_sample_filter_type_names[i];
+ if (type_name->type == filter->type)
+ return sysfs_emit(buf, "%s\n", type_name->name);
+ }
+ return -EINVAL;
+}
+
+static ssize_t type_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_sample_filter *filter = container_of(kobj,
+ struct damon_sysfs_sample_filter, kobj);
+ ssize_t ret = -EINVAL;
+ int i = 0;
+
+ for (; i < ARRAY_SIZE(damon_sysfs_sample_filter_type_names); i++) {
+ const struct damon_sysfs_sample_filter_type_name *type_name;
+
+ type_name = &damon_sysfs_sample_filter_type_names[i];
+ if (sysfs_streq(buf, type_name->name)) {
+ filter->type = type_name->type;
+ ret = count;
+ break;
+ }
+ }
+ return ret;
+}
+
+static ssize_t matching_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_sample_filter *filter = container_of(kobj,
+ struct damon_sysfs_sample_filter, kobj);
+
+ return sysfs_emit(buf, "%c\n", filter->matching ? 'Y' : 'N');
+}
+
+static ssize_t matching_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_sample_filter *filter = container_of(kobj,
+ struct damon_sysfs_sample_filter, kobj);
+ bool matching;
+ int err = kstrtobool(buf, &matching);
+
+ if (err)
+ return err;
+
+ filter->matching = matching;
+ return count;
+}
+
+static ssize_t allow_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_sample_filter *filter = container_of(kobj,
+ struct damon_sysfs_sample_filter, kobj);
+
+ return sysfs_emit(buf, "%c\n", filter->allow ? 'Y' : 'N');
+}
+
+static ssize_t allow_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_sample_filter *filter = container_of(kobj,
+ struct damon_sysfs_sample_filter, kobj);
+ bool allow;
+ int err = kstrtobool(buf, &allow);
+
+ if (err)
+ return err;
+
+ filter->allow = allow;
+ return count;
+}
+
+static ssize_t cpumask_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ struct damon_sysfs_sample_filter *filter = container_of(kobj,
+ struct damon_sysfs_sample_filter, kobj);
+
+ return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(&filter->cpumask));
+}
+
+static ssize_t cpumask_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct damon_sysfs_sample_filter *filter = container_of(kobj,
+ struct damon_sysfs_sample_filter, kobj);
+ cpumask_t cpumask;
+ int err = cpulist_parse(buf, &cpumask);
+
+ if (err)
+ return err;
+ filter->cpumask = cpumask;
+ return count;
+}
+
+static void damon_sysfs_sample_filter_release(struct kobject *kobj)
+{
+ struct damon_sysfs_sample_filter *filter = container_of(kobj,
+ struct damon_sysfs_sample_filter, kobj);
+
+ kfree(filter);
+}
+
+static struct kobj_attribute damon_sysfs_sample_filter_type_attr =
+ __ATTR_RW_MODE(type, 0600);
+
+static struct kobj_attribute damon_sysfs_sample_filter_matching_attr =
+ __ATTR_RW_MODE(matching, 0600);
+
+static struct kobj_attribute damon_sysfs_sample_filter_allow_attr =
+ __ATTR_RW_MODE(allow, 0600);
+
+static struct kobj_attribute damon_sysfs_sample_filter_cpumask_attr =
+ __ATTR_RW_MODE(cpumask, 0600);
+
+static struct attribute *damon_sysfs_sample_filter_attrs[] = {
+ &damon_sysfs_sample_filter_type_attr.attr,
+ &damon_sysfs_sample_filter_matching_attr.attr,
+ &damon_sysfs_sample_filter_allow_attr.attr,
+ &damon_sysfs_sample_filter_cpumask_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(damon_sysfs_sample_filter);
+
+static const struct kobj_type damon_sysfs_sample_filter_ktype = {
+ .release = damon_sysfs_sample_filter_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damon_sysfs_sample_filter_groups,
+};
+
+/*
+ * access check report filters directory
+ */
+
+struct damon_sysfs_sample_filters {
+ struct kobject kobj;
+ struct damon_sysfs_sample_filter **filters_arr;
+ int nr;
+};
+
+static struct damon_sysfs_sample_filters *
+damon_sysfs_sample_filters_alloc(void)
+{
+ return kzalloc(sizeof(struct damon_sysfs_sample_filters), GFP_KERNEL);
+}
+
+static void damon_sysfs_sample_filters_rm_dirs(
+ struct damon_sysfs_sample_filters *filters)
+{
+ struct damon_sysfs_sample_filter **filters_arr = filters->filters_arr;
+ int i;
+
+ for (i = 0; i < filters->nr; i++)
+ kobject_put(&filters_arr[i]->kobj);
+ filters->nr = 0;
+ kfree(filters_arr);
+ filters->filters_arr = NULL;
+}
+
+static int damon_sysfs_sample_filters_add_dirs(
+ struct damon_sysfs_sample_filters *filters, int nr_filters)
+{
+ struct damon_sysfs_sample_filter **filters_arr, *filter;
+ int err, i;
+
+ damon_sysfs_sample_filters_rm_dirs(filters);
+ if (!nr_filters)
+ return 0;
+
+ filters_arr = kmalloc_array(nr_filters, sizeof(*filters_arr),
+ GFP_KERNEL | __GFP_NOWARN);
+ if (!filters_arr)
+ return -ENOMEM;
+ filters->filters_arr = filters_arr;
+
+ for (i = 0; i < nr_filters; i++) {
+ filter = damon_sysfs_sample_filter_alloc();
+ if (!filter) {
+ damon_sysfs_sample_filters_rm_dirs(filters);
+ return -ENOMEM;
+ }
+
+ err = kobject_init_and_add(&filter->kobj,
+ &damon_sysfs_sample_filter_ktype,
+ &filters->kobj, "%d", i);
+ if (err) {
+ kobject_put(&filter->kobj);
+ damon_sysfs_sample_filters_rm_dirs(filters);
+ return err;
+ }
+
+ filters_arr[i] = filter;
+ filters->nr++;
+ }
+ return 0;
+}
+
+static ssize_t nr_filters_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_sample_filters *filters = container_of(kobj,
+ struct damon_sysfs_sample_filters, kobj);
+
+ return sysfs_emit(buf, "%d\n", filters->nr);
+}
+
+static ssize_t nr_filters_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_sample_filters *filters;
+ int nr, err = kstrtoint(buf, 0, &nr);
+
+ if (err)
+ return err;
+ if (nr < 0)
+ return -EINVAL;
+
+ filters = container_of(kobj, struct damon_sysfs_sample_filters, kobj);
+
+ if (!mutex_trylock(&damon_sysfs_lock))
+ return -EBUSY;
+ err = damon_sysfs_sample_filters_add_dirs(filters, nr);
+ mutex_unlock(&damon_sysfs_lock);
+ if (err)
+ return err;
+
+ return count;
+}
+
+static void damon_sysfs_sample_filters_release(struct kobject *kobj)
+{
+ kfree(container_of(kobj, struct damon_sysfs_sample_filters, kobj));
+}
+
+static struct kobj_attribute damon_sysfs_sample_filters_nr_attr =
+ __ATTR_RW_MODE(nr_filters, 0600);
+
+static struct attribute *damon_sysfs_sample_filters_attrs[] = {
+ &damon_sysfs_sample_filters_nr_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(damon_sysfs_sample_filters);
+
+static const struct kobj_type damon_sysfs_sample_filters_ktype = {
+ .release = damon_sysfs_sample_filters_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damon_sysfs_sample_filters_groups,
+};
+
+/*
+ * access check primitives directory
+ */
+
+struct damon_sysfs_primitives {
+ struct kobject kobj;
+ bool page_table;
+ bool page_fault;
+};
+
+static struct damon_sysfs_primitives *damon_sysfs_primitives_alloc(
+ bool page_table, bool page_fault)
+{
+ struct damon_sysfs_primitives *primitives = kmalloc(
+ sizeof(*primitives), GFP_KERNEL);
+
+ if (!primitives)
+ return NULL;
+
+ primitives->kobj = (struct kobject){};
+ primitives->page_table = page_table;
+ primitives->page_fault = page_fault;
+ return primitives;
+}
+
+static ssize_t page_table_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_primitives *primitives = container_of(kobj,
+ struct damon_sysfs_primitives, kobj);
+
+ return sysfs_emit(buf, "%c\n", primitives->page_table ? 'Y' : 'N');
+}
+
+static ssize_t page_table_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_primitives *primitives = container_of(kobj,
+ struct damon_sysfs_primitives, kobj);
+ bool enable;
+ int err = kstrtobool(buf, &enable);
+
+ if (err)
+ return err;
+ primitives->page_table = enable;
+ return count;
+}
+
+static ssize_t page_fault_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct damon_sysfs_primitives *primitives = container_of(kobj,
+ struct damon_sysfs_primitives, kobj);
+
+ return sysfs_emit(buf, "%c\n", primitives->page_fault ? 'Y' : 'N');
+}
+
+static ssize_t page_fault_store(struct kobject *kobj,
+ struct kobj_attribute *attr, const char *buf, size_t count)
+{
+ struct damon_sysfs_primitives *primitives = container_of(kobj,
+ struct damon_sysfs_primitives, kobj);
+ bool enable;
+ int err = kstrtobool(buf, &enable);
+
+ if (err)
+ return err;
+ primitives->page_fault = enable;
+ return count;
+}
+
+static void damon_sysfs_primitives_release(struct kobject *kobj)
+{
+ struct damon_sysfs_primitives *primitives = container_of(kobj,
+ struct damon_sysfs_primitives, kobj);
+
+ kfree(primitives);
+}
+
+static struct kobj_attribute damon_sysfs_primitives_page_table_attr =
+ __ATTR_RW_MODE(page_table, 0600);
+
+static struct kobj_attribute damon_sysfs_primitives_page_fault_attr =
+ __ATTR_RW_MODE(page_fault, 0600);
+
+static struct attribute *damon_sysfs_primitives_attrs[] = {
+ &damon_sysfs_primitives_page_table_attr.attr,
+ &damon_sysfs_primitives_page_fault_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(damon_sysfs_primitives);
+
+static const struct kobj_type damon_sysfs_primitives_ktype = {
+ .release = damon_sysfs_primitives_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damon_sysfs_primitives_groups,
+};
+
+/*
+ * sample directory
+ */
+
+struct damon_sysfs_sample {
+ struct kobject kobj;
+ struct damon_sysfs_primitives *primitives;
+ struct damon_sysfs_sample_filters *filters;
+};
+
+static struct damon_sysfs_sample *damon_sysfs_sample_alloc(void)
+{
+ struct damon_sysfs_sample *sample = kmalloc(
+ sizeof(*sample), GFP_KERNEL);
+
+ if (!sample)
+ return NULL;
+ sample->kobj = (struct kobject){};
+ return sample;
+}
+
+static int damon_sysfs_sample_add_dirs(
+ struct damon_sysfs_sample *sample)
+{
+ struct damon_sysfs_primitives *primitives;
+ struct damon_sysfs_sample_filters *filters;
+ int err;
+
+ primitives = damon_sysfs_primitives_alloc(true, false);
+ if (!primitives)
+ return -ENOMEM;
+ err = kobject_init_and_add(&primitives->kobj,
+ &damon_sysfs_primitives_ktype, &sample->kobj,
+ "primitives");
+ if (err)
+ goto put_primitives_out;
+ sample->primitives = primitives;
+
+ filters = damon_sysfs_sample_filters_alloc();
+ if (!filters) {
+ err = -ENOMEM;
+ goto put_primitives_out;
+ }
+ err = kobject_init_and_add(&filters->kobj,
+ &damon_sysfs_sample_filters_ktype, &sample->kobj,
+ "filters");
+ if (err)
+ goto put_filters_out;
+ sample->filters = filters;
+ return 0;
+put_filters_out:
+ kobject_put(&filters->kobj);
+ sample->filters = NULL;
+put_primitives_out:
+ kobject_put(&primitives->kobj);
+ sample->primitives = NULL;
+ return err;
+}
+
+static void damon_sysfs_sample_rm_dirs(
+ struct damon_sysfs_sample *sample)
+{
+ if (sample->primitives)
+ kobject_put(&sample->primitives->kobj);
+ if (sample->filters) {
+ damon_sysfs_sample_filters_rm_dirs(sample->filters);
+ kobject_put(&sample->filters->kobj);
+ }
+}
+
+static void damon_sysfs_sample_release(struct kobject *kobj)
+{
+ kfree(container_of(kobj, struct damon_sysfs_sample, kobj));
+}
+
+static struct attribute *damon_sysfs_sample_attrs[] = {
+ NULL,
+};
+ATTRIBUTE_GROUPS(damon_sysfs_sample);
+
+static const struct kobj_type damon_sysfs_sample_ktype = {
+ .release = damon_sysfs_sample_release,
+ .sysfs_ops = &kobj_sysfs_ops,
+ .default_groups = damon_sysfs_sample_groups,
+};
+
/*
* monitoring_attrs directory
*/
@@ -755,6 +1232,7 @@ struct damon_sysfs_attrs {
struct kobject kobj;
struct damon_sysfs_intervals *intervals;
struct damon_sysfs_ul_range *nr_regions_range;
+ struct damon_sysfs_sample *sample;
};
static struct damon_sysfs_attrs *damon_sysfs_attrs_alloc(void)
@@ -771,6 +1249,7 @@ static int damon_sysfs_attrs_add_dirs(struct damon_sysfs_attrs *attrs)
{
struct damon_sysfs_intervals *intervals;
struct damon_sysfs_ul_range *nr_regions_range;
+ struct damon_sysfs_sample *sample;
int err;
intervals = damon_sysfs_intervals_alloc(5000, 100000, 60000000);
@@ -799,8 +1278,26 @@ static int damon_sysfs_attrs_add_dirs(struct damon_sysfs_attrs *attrs)
if (err)
goto put_nr_regions_intervals_out;
attrs->nr_regions_range = nr_regions_range;
+
+ sample = damon_sysfs_sample_alloc();
+ if (!sample) {
+ err = -ENOMEM;
+ goto put_nr_regions_intervals_out;
+ }
+ err = kobject_init_and_add(&sample->kobj,
+ &damon_sysfs_sample_ktype, &attrs->kobj,
+ "sample");
+ if (err)
+ goto put_sample_out;
+ err = damon_sysfs_sample_add_dirs(sample);
+ if (err)
+ goto put_sample_out;
+ attrs->sample = sample;
return 0;
+put_sample_out:
+ kobject_put(&sample->kobj);
+ attrs->sample = NULL;
put_nr_regions_intervals_out:
kobject_put(&nr_regions_range->kobj);
attrs->nr_regions_range = NULL;
@@ -817,6 +1314,8 @@ static void damon_sysfs_attrs_rm_dirs(struct damon_sysfs_attrs *attrs)
kobject_put(&attrs->nr_regions_range->kobj);
damon_sysfs_intervals_rm_dirs(attrs->intervals);
kobject_put(&attrs->intervals->kobj);
+ damon_sysfs_sample_rm_dirs(attrs->sample);
+ kobject_put(&attrs->sample->kobj);
}
static void damon_sysfs_attrs_release(struct kobject *kobj)
--
2.43.0
next prev parent reply other threads:[~2026-04-23 0:43 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-23 0:42 [RFC PATCH v3 0/4] mm/damon: introduce perf event based access check Akinobu Mita
2026-04-23 0:42 ` Akinobu Mita [this message]
2026-04-23 1:21 ` [RFC PATCH v3 1/4] mm/damon/core: add code borrowed from report-based monitoring work sashiko-bot
2026-04-23 0:42 ` [RFC PATCH v3 2/4] mm/damon/core: add common code for perf event based access check Akinobu Mita
2026-04-23 1:58 ` sashiko-bot
2026-04-23 0:42 ` [RFC PATCH v3 3/4] mm/damon/vaddr: support " Akinobu Mita
2026-04-23 2:48 ` sashiko-bot
2026-04-23 0:42 ` [RFC PATCH v3 4/4] mm/damon/paddr: " Akinobu Mita
2026-04-23 3:22 ` sashiko-bot
2026-04-23 4:34 ` [RFC PATCH v3 0/4] mm/damon: introduce " SeongJae Park
2026-04-24 3:27 ` Akinobu Mita
2026-04-24 23:31 ` SeongJae Park
2026-04-25 12:33 ` Akinobu Mita
2026-04-25 15:33 ` SeongJae Park
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260423004211.7037-2-akinobu.mita@gmail.com \
--to=akinobu.mita@gmail.com \
--cc=damon@lists.linux.dev \
--cc=linux-perf-users@vger.kernel.org \
--cc=sj@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox