linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Sourav Panda <souravpanda@google.com>
To: mathieu.desnoyers@efficios.com, willy@infradead.org,
	david@redhat.com,  pasha.tatashin@soleen.com,
	rientjes@google.com, akpm@linux-foundation.org,
	 linux-mm@kvack.org, linux-kernel@vger.kernel.org,
	weixugc@google.com,  gthelen@google.com, souravpanda@google.com,
	surenb@google.com
Subject: [RFC PATCH 5/6] mm: trigger unmerge and remove SELECTIVE KSM partition
Date: Fri, 21 Mar 2025 17:37:28 +0000	[thread overview]
Message-ID: <20250321173729.3175898-6-souravpanda@google.com> (raw)
In-Reply-To: <20250321173729.3175898-1-souravpanda@google.com>

Trigger unmerge or remove a partition using the
following sysfs interface:

Triggering an unmerge for a specific partition:
  echo "pid" > /sys/kernel/mm/ksm/partition_name/trigger_unmerge

Removing a partition:
  echo "partition_to_remove" >
	/sys/kernel/mm/ksm/control/remove_partition

Limitation of current implementation: On carrying out trigger_unmerge,
we unmerge all rmap items which is wrong. We should only unmerge the
rmap items that belong to the partition where we called unmerge.

Another limitation is that we do not specify the address range when
echoing into trigger unmerge. Intentionally left out till until we
determine the implementation feasibility.

Signed-off-by: Sourav Panda <souravpanda@google.com>
---
 mm/ksm.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)

diff --git a/mm/ksm.c b/mm/ksm.c
index b575250aaf45..fd7626d5d8c9 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -2556,6 +2556,31 @@ static void ksm_sync_merge(struct mm_struct *mm,
 	put_page(page);
 }
 
+static void ksm_sync_unmerge(struct mm_struct *mm)
+{
+	struct mm_slot *slot;
+	struct ksm_mm_slot *mm_slot;
+
+	struct vm_area_struct *vma;
+	struct vma_iterator vmi;
+
+	slot = mm_slot_lookup(mm_slots_hash, mm);
+	mm_slot = container_of(slot, struct ksm_mm_slot, slot);
+
+	ksm_scan.address = 0;
+	vma_iter_init(&vmi, mm, ksm_scan.address);
+
+	mmap_read_lock(mm);
+	for_each_vma(vmi, vma) {
+		if (!(vma->vm_flags & VM_MERGEABLE) || !vma->anon_vma)
+			continue;
+		unmerge_ksm_pages(vma, vma->vm_start, vma->vm_end, false);
+	}
+	remove_trailing_rmap_items(&mm_slot->rmap_list);
+
+	mmap_read_unlock(mm);
+}
+
 #else /* CONFIG_SELECTIVE_KSM */
 /*
  * Calculate skip age for the ksm page age. The age determines how often
@@ -3644,6 +3669,58 @@ static ssize_t trigger_merge_store(struct kobject *kobj,
 }
 KSM_ATTR(trigger_merge);
 
+static ssize_t trigger_unmerge_show(struct kobject *kobj,
+				    struct kobj_attribute *attr,
+				    char *buf)
+{
+	return -EINVAL;	/* Not yet implemented */
+}
+
+static ssize_t trigger_unmerge_store(struct kobject *kobj,
+				     struct kobj_attribute *attr,
+				     const char *buf, size_t count)
+{
+	pid_t pid;
+	char *input, *ptr;
+	int ret;
+	struct task_struct *task;
+	struct mm_struct *mm;
+
+	input = kstrdup(buf, GFP_KERNEL);
+	if (!input)
+		return -ENOMEM;
+
+	ptr = strim(input);
+	ret = kstrtoint(ptr, 10, &pid);
+	kfree(input);
+
+	/* Find the mm_struct */
+	rcu_read_lock();
+	task = find_task_by_vpid(pid);
+	if (!task) {
+		rcu_read_unlock();
+		return -ESRCH;
+	}
+
+	get_task_struct(task);
+
+	rcu_read_unlock();
+	mm = get_task_mm(task);
+	put_task_struct(task);
+
+	if (!mm)
+		return -EINVAL;
+
+	mutex_lock(&ksm_thread_mutex);
+	wait_while_offlining();
+	ksm_sync_unmerge(mm);
+	mutex_unlock(&ksm_thread_mutex);
+
+	mmput(mm);
+	return count;
+}
+KSM_ATTR(trigger_unmerge);
+
 #ifdef CONFIG_NUMA
 static ssize_t merge_across_nodes_show(struct kobject *kobj,
 				       struct kobj_attribute *attr, char *buf)
@@ -4044,6 +4121,7 @@ static struct attribute *ksm_attrs[] = {
 	&pages_to_scan_attr.attr,
 	&run_attr.attr,
 	&trigger_merge_attr.attr,
+	&trigger_unmerge_attr.attr,
 	&pages_scanned_attr.attr,
 	&pages_shared_attr.attr,
 	&pages_sharing_attr.attr,
@@ -4156,9 +4234,51 @@ static ssize_t add_partition_store(struct kobject *kobj,
 static struct kobj_attribute add_kobj_attr = __ATTR(add_partition, 0220, NULL,
 						    add_partition_store);
 
+static ssize_t remove_partition_store(struct kobject *kobj,
+				      struct kobj_attribute *attr,
+				      const char *buf, size_t count)
+{
+	struct partition_kobj *partition;
+	struct partition_kobj *partition_found = NULL;
+	char partition_name[50];
+	int err = 0;
+
+	if (sscanf(buf, "%31s", partition_name) != 1)
+		return -EINVAL;
+
+	mutex_lock(&ksm_thread_mutex);
+
+	list_for_each_entry(partition, &partition_list, list) {
+		if (strcmp(kobject_name(partition->kobj), partition_name) == 0) {
+			partition_found = partition;
+			break;
+		}
+	}
+
+	if (!partition_found) {
+		err = -ENOENT;
+		goto unlock;
+	}
+
+	unmerge_and_remove_all_rmap_items();
+
+	kobject_put(partition_found->kobj);
+	list_del(&partition_found->list);
+	kfree(partition_found->root_stable_tree);
+	kfree(partition_found);
+
+unlock:
+	mutex_unlock(&ksm_thread_mutex);
+	return err ? err : count;
+}
+
+static struct kobj_attribute rm_kobj_attr = __ATTR(remove_partition, 0220, NULL,
+						   remove_partition_store);
+
 /* Array of attributes for base kobject */
 static struct attribute *ksm_base_attrs[] = {
 	&add_kobj_attr.attr,
+	&rm_kobj_attr.attr,
 	NULL,  /* NULL-terminated */
 };
 
-- 
2.49.0.395.g12beb8f557-goog



  parent reply	other threads:[~2025-03-21 17:37 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-21 17:37 [RFC PATCH 0/6] Selective KSM: Synchronous and Partitioned Merging Sourav Panda
2025-03-21 17:37 ` [RFC PATCH 1/6] mm: introduce SELECTIVE_KSM KConfig Sourav Panda
2025-03-21 17:37 ` [RFC PATCH 2/6] mm: make Selective KSM synchronous Sourav Panda
2025-03-21 17:37 ` [RFC PATCH 3/6] mm: make Selective KSM partitioned Sourav Panda
2025-03-21 17:37 ` [RFC PATCH 4/6] mm: create dedicated trees for SELECTIVE KSM partitions Sourav Panda
2025-03-21 17:37 ` Sourav Panda [this message]
2025-03-21 17:37 ` [RFC PATCH 6/6] mm: syscall alternative for SELECTIVE_KSM Sourav Panda

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=20250321173729.3175898-6-souravpanda@google.com \
    --to=souravpanda@google.com \
    --cc=akpm@linux-foundation.org \
    --cc=david@redhat.com \
    --cc=gthelen@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=pasha.tatashin@soleen.com \
    --cc=rientjes@google.com \
    --cc=surenb@google.com \
    --cc=weixugc@google.com \
    --cc=willy@infradead.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