|
@@ -1330,29 +1330,71 @@ static struct hstate *kobj_to_hstate(struct kobject *kobj)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-static ssize_t nr_hugepages_show(struct kobject *kobj,
|
|
|
+static ssize_t nr_hugepages_show_common(struct kobject *kobj,
|
|
|
struct kobj_attribute *attr, char *buf)
|
|
|
{
|
|
|
struct hstate *h = kobj_to_hstate(kobj);
|
|
|
return sprintf(buf, "%lu\n", h->nr_huge_pages);
|
|
|
}
|
|
|
-static ssize_t nr_hugepages_store(struct kobject *kobj,
|
|
|
- struct kobj_attribute *attr, const char *buf, size_t count)
|
|
|
+static ssize_t nr_hugepages_store_common(bool obey_mempolicy,
|
|
|
+ struct kobject *kobj, struct kobj_attribute *attr,
|
|
|
+ const char *buf, size_t len)
|
|
|
{
|
|
|
int err;
|
|
|
- unsigned long input;
|
|
|
+ unsigned long count;
|
|
|
struct hstate *h = kobj_to_hstate(kobj);
|
|
|
+ NODEMASK_ALLOC(nodemask_t, nodes_allowed);
|
|
|
|
|
|
- err = strict_strtoul(buf, 10, &input);
|
|
|
+ err = strict_strtoul(buf, 10, &count);
|
|
|
if (err)
|
|
|
return 0;
|
|
|
|
|
|
- h->max_huge_pages = set_max_huge_pages(h, input, &node_online_map);
|
|
|
+ if (!(obey_mempolicy && init_nodemask_of_mempolicy(nodes_allowed))) {
|
|
|
+ NODEMASK_FREE(nodes_allowed);
|
|
|
+ nodes_allowed = &node_online_map;
|
|
|
+ }
|
|
|
+ h->max_huge_pages = set_max_huge_pages(h, count, nodes_allowed);
|
|
|
|
|
|
- return count;
|
|
|
+ if (nodes_allowed != &node_online_map)
|
|
|
+ NODEMASK_FREE(nodes_allowed);
|
|
|
+
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t nr_hugepages_show(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ return nr_hugepages_show_common(kobj, attr, buf);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t nr_hugepages_store(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, const char *buf, size_t len)
|
|
|
+{
|
|
|
+ return nr_hugepages_store_common(false, kobj, attr, buf, len);
|
|
|
}
|
|
|
HSTATE_ATTR(nr_hugepages);
|
|
|
|
|
|
+#ifdef CONFIG_NUMA
|
|
|
+
|
|
|
+/*
|
|
|
+ * hstate attribute for optionally mempolicy-based constraint on persistent
|
|
|
+ * huge page alloc/free.
|
|
|
+ */
|
|
|
+static ssize_t nr_hugepages_mempolicy_show(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, char *buf)
|
|
|
+{
|
|
|
+ return nr_hugepages_show_common(kobj, attr, buf);
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t nr_hugepages_mempolicy_store(struct kobject *kobj,
|
|
|
+ struct kobj_attribute *attr, const char *buf, size_t len)
|
|
|
+{
|
|
|
+ return nr_hugepages_store_common(true, kobj, attr, buf, len);
|
|
|
+}
|
|
|
+HSTATE_ATTR(nr_hugepages_mempolicy);
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
static ssize_t nr_overcommit_hugepages_show(struct kobject *kobj,
|
|
|
struct kobj_attribute *attr, char *buf)
|
|
|
{
|
|
@@ -1408,6 +1450,9 @@ static struct attribute *hstate_attrs[] = {
|
|
|
&free_hugepages_attr.attr,
|
|
|
&resv_hugepages_attr.attr,
|
|
|
&surplus_hugepages_attr.attr,
|
|
|
+#ifdef CONFIG_NUMA
|
|
|
+ &nr_hugepages_mempolicy_attr.attr,
|
|
|
+#endif
|
|
|
NULL,
|
|
|
};
|
|
|
|
|
@@ -1574,9 +1619,9 @@ static unsigned int cpuset_mems_nr(unsigned int *array)
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_SYSCTL
|
|
|
-int hugetlb_sysctl_handler(struct ctl_table *table, int write,
|
|
|
- void __user *buffer,
|
|
|
- size_t *length, loff_t *ppos)
|
|
|
+static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
|
|
|
+ struct ctl_table *table, int write,
|
|
|
+ void __user *buffer, size_t *length, loff_t *ppos)
|
|
|
{
|
|
|
struct hstate *h = &default_hstate;
|
|
|
unsigned long tmp;
|
|
@@ -1588,13 +1633,39 @@ int hugetlb_sysctl_handler(struct ctl_table *table, int write,
|
|
|
table->maxlen = sizeof(unsigned long);
|
|
|
proc_doulongvec_minmax(table, write, buffer, length, ppos);
|
|
|
|
|
|
- if (write)
|
|
|
- h->max_huge_pages = set_max_huge_pages(h, tmp,
|
|
|
- &node_online_map);
|
|
|
+ if (write) {
|
|
|
+ NODEMASK_ALLOC(nodemask_t, nodes_allowed);
|
|
|
+ if (!(obey_mempolicy &&
|
|
|
+ init_nodemask_of_mempolicy(nodes_allowed))) {
|
|
|
+ NODEMASK_FREE(nodes_allowed);
|
|
|
+ nodes_allowed = &node_states[N_HIGH_MEMORY];
|
|
|
+ }
|
|
|
+ h->max_huge_pages = set_max_huge_pages(h, tmp, nodes_allowed);
|
|
|
+
|
|
|
+ if (nodes_allowed != &node_states[N_HIGH_MEMORY])
|
|
|
+ NODEMASK_FREE(nodes_allowed);
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+int hugetlb_sysctl_handler(struct ctl_table *table, int write,
|
|
|
+ void __user *buffer, size_t *length, loff_t *ppos)
|
|
|
+{
|
|
|
+
|
|
|
+ return hugetlb_sysctl_handler_common(false, table, write,
|
|
|
+ buffer, length, ppos);
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef CONFIG_NUMA
|
|
|
+int hugetlb_mempolicy_sysctl_handler(struct ctl_table *table, int write,
|
|
|
+ void __user *buffer, size_t *length, loff_t *ppos)
|
|
|
+{
|
|
|
+ return hugetlb_sysctl_handler_common(true, table, write,
|
|
|
+ buffer, length, ppos);
|
|
|
+}
|
|
|
+#endif /* CONFIG_NUMA */
|
|
|
+
|
|
|
int hugetlb_treat_movable_handler(struct ctl_table *table, int write,
|
|
|
void __user *buffer,
|
|
|
size_t *length, loff_t *ppos)
|