[RFC PATCH 5/6] mm: trigger unmerge and remove SELECTIVE KSM partition

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>
---
 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





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux