Create a sysfs interface to partition the KSM merge space. We add a new sysfs file, namely add_partition. Which is used to specify the name of the new partition. Once a partition is created, we would get the traditional files typcally available in KSM under each partition. This sysfs interface changes are in preparation of the following patch that shall actually partition the merge space (e.g., prevent page-comparison and merging across partitions). KSM_SYSFS=/sys/kernel/mm/ksm echo "part_1" > ${KSM_SYSFS}/ksm/control/add_partition ls ${KSM_SYSFS}/part_1/ pages_scanned pages_to_scan sleep_millisecs ... echo "pid start_addr end_addr" > ${KSM_SYSFS}/part_1/trigger_merge Signed-off-by: Sourav Panda <souravpanda@xxxxxxxxxx> --- mm/ksm.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 95 insertions(+), 6 deletions(-) diff --git a/mm/ksm.c b/mm/ksm.c index b2f184557ed9..927e257c48b5 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -3832,7 +3832,17 @@ static ssize_t full_scans_show(struct kobject *kobj, } KSM_ATTR_RO(full_scans); -#ifndef CONFIG_SELECTIVE_KSM +#ifdef CONFIG_SELECTIVE_KSM +static struct kobject *ksm_base_kobj; + +struct partition_kobj { + struct kobject *kobj; + struct list_head list; +}; + +static LIST_HEAD(partition_list); + +#else /* CONFIG_SELECTIVE_KSM */ static ssize_t smart_scan_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -4015,15 +4025,22 @@ static struct attribute *ksm_attrs[] = { static const struct attribute_group ksm_attr_group = { .attrs = ksm_attrs, +#ifndef CONFIG_SELECTIVE_KSM .name = "ksm", +#endif }; -static int __init ksm_sysfs_init(void) +static int __init ksm_sysfs_init(struct kobject *kobj, + const struct attribute_group *grp) { - return sysfs_create_group(mm_kobj, &ksm_attr_group); + int err; + + err = sysfs_create_group(kobj, grp); + return err; } #else /* CONFIG_SYSFS */ -static int __init ksm_sysfs_init(void) +static int __init ksm_sysfs_init(struct kobject *kobj, + const struct attribute_group *grp) { ksm_run = KSM_RUN_MERGE; /* no way for user to start it */ return 0; @@ -4031,9 +4048,81 @@ static int __init ksm_sysfs_init(void) #endif /* CONFIG_SYSFS */ #ifdef CONFIG_SELECTIVE_KSM +static ssize_t add_partition_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct partition_kobj *new_partition_kobj; + char partition_name[50]; + int err; + + mutex_lock(&ksm_thread_mutex); + + if (count >= sizeof(partition_name)) { + err = -EINVAL; /* Prevent buffer overflow */ + goto unlock; + } + + snprintf(partition_name, sizeof(partition_name), + "%.*s", (int)(count - 1), buf); /* Remove newline */ + + /* Allocate memory for new dynamic kobject entry */ + new_partition_kobj = kmalloc(sizeof(*new_partition_kobj), GFP_KERNEL); + if (!new_partition_kobj) { + err = -ENOMEM; + goto unlock; + } + + new_partition_kobj->kobj = kobject_create_and_add(partition_name, + ksm_base_kobj); + if (!new_partition_kobj) { + kfree(new_partition_kobj); + err = -ENOMEM; + goto unlock; + } + + err = sysfs_create_group(new_partition_kobj->kobj, &ksm_attr_group); + if (err) { + pr_err("ksm: register sysfs failed\n"); + kfree(new_partition_kobj); + err = -ENOMEM; + goto unlock; + } + + list_add(&new_partition_kobj->list, &partition_list); + +unlock: + mutex_unlock(&ksm_thread_mutex); + return err ? err : count; +} + +static struct kobj_attribute add_kobj_attr = __ATTR(add_partition, 0220, NULL, + add_partition_store); + +/* Array of attributes for base kobject */ +static struct attribute *ksm_base_attrs[] = { + &add_kobj_attr.attr, + NULL, /* NULL-terminated */ +}; + +/* Attribute group for base kobject */ +static struct attribute_group ksm_base_attr_group = { + .name = "control", + .attrs = ksm_base_attrs, +}; + static int __init ksm_thread_sysfs_init(void) { - return ksm_sysfs_init(); + int err; + + ksm_base_kobj = kobject_create_and_add("ksm", mm_kobj); + if (!ksm_base_kobj) { + err = -ENOMEM; + return err; + } + + err = ksm_sysfs_init(ksm_base_kobj, &ksm_base_attr_group); + return err; } #else /* CONFIG_SELECTIVE_KSM */ static int __init ksm_thread_sysfs_init(void) @@ -4048,7 +4137,7 @@ static int __init ksm_thread_sysfs_init(void) return err; } - err = ksm_sysfs_init(); + err = ksm_sysfs_init(mm_kobj, &ksm_attr_group); if (err) { pr_err("ksm: register sysfs failed\n"); kthread_stop(ksm_thread); -- 2.49.0.395.g12beb8f557-goog