Commit adbe8726 authored by Eric B Munson's avatar Eric B Munson Committed by Linus Torvalds

hugetlb: do not allow pagesize >= MAX_ORDER pool adjustment

Huge pages with order >= MAX_ORDER must be allocated at boot via the
kernel command line, they cannot be allocated or freed once the kernel is
up and running.  Currently we allow values to be written to the sysfs and
sysctl files controling pool size for these huge page sizes.  This patch
makes the store functions for nr_hugepages and nr_overcommit_hugepages
return -EINVAL when the pool for a page size >= MAX_ORDER is changed.

[akpm@linux-foundation.org: avoid multiple return paths in nr_hugepages_store_common()]
[caiqian@redhat.com: add checking in hugetlb_overcommit_handler()]
Signed-off-by: default avatarEric B Munson <emunson@mgebm.net>
Reported-by: default avatarCAI Qian <caiqian@redhat.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: Nishanth Aravamudan <nacc@us.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 08d4a246
...@@ -1363,6 +1363,7 @@ static ssize_t nr_hugepages_show_common(struct kobject *kobj, ...@@ -1363,6 +1363,7 @@ static ssize_t nr_hugepages_show_common(struct kobject *kobj,
return sprintf(buf, "%lu\n", nr_huge_pages); return sprintf(buf, "%lu\n", nr_huge_pages);
} }
static ssize_t nr_hugepages_store_common(bool obey_mempolicy, static ssize_t nr_hugepages_store_common(bool obey_mempolicy,
struct kobject *kobj, struct kobj_attribute *attr, struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t len) const char *buf, size_t len)
...@@ -1375,11 +1376,16 @@ static ssize_t nr_hugepages_store_common(bool obey_mempolicy, ...@@ -1375,11 +1376,16 @@ static ssize_t nr_hugepages_store_common(bool obey_mempolicy,
err = strict_strtoul(buf, 10, &count); err = strict_strtoul(buf, 10, &count);
if (err) { if (err) {
NODEMASK_FREE(nodes_allowed); err = 0; /* This seems wrong */
return 0; goto out;
} }
h = kobj_to_hstate(kobj, &nid); h = kobj_to_hstate(kobj, &nid);
if (h->order >= MAX_ORDER) {
err = -EINVAL;
goto out;
}
if (nid == NUMA_NO_NODE) { if (nid == NUMA_NO_NODE) {
/* /*
* global hstate attribute * global hstate attribute
...@@ -1405,6 +1411,9 @@ static ssize_t nr_hugepages_store_common(bool obey_mempolicy, ...@@ -1405,6 +1411,9 @@ static ssize_t nr_hugepages_store_common(bool obey_mempolicy,
NODEMASK_FREE(nodes_allowed); NODEMASK_FREE(nodes_allowed);
return len; return len;
out:
NODEMASK_FREE(nodes_allowed);
return err;
} }
static ssize_t nr_hugepages_show(struct kobject *kobj, static ssize_t nr_hugepages_show(struct kobject *kobj,
...@@ -1447,6 +1456,7 @@ static ssize_t nr_overcommit_hugepages_show(struct kobject *kobj, ...@@ -1447,6 +1456,7 @@ static ssize_t nr_overcommit_hugepages_show(struct kobject *kobj,
struct hstate *h = kobj_to_hstate(kobj, NULL); struct hstate *h = kobj_to_hstate(kobj, NULL);
return sprintf(buf, "%lu\n", h->nr_overcommit_huge_pages); return sprintf(buf, "%lu\n", h->nr_overcommit_huge_pages);
} }
static ssize_t nr_overcommit_hugepages_store(struct kobject *kobj, static ssize_t nr_overcommit_hugepages_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t count) struct kobj_attribute *attr, const char *buf, size_t count)
{ {
...@@ -1454,6 +1464,9 @@ static ssize_t nr_overcommit_hugepages_store(struct kobject *kobj, ...@@ -1454,6 +1464,9 @@ static ssize_t nr_overcommit_hugepages_store(struct kobject *kobj,
unsigned long input; unsigned long input;
struct hstate *h = kobj_to_hstate(kobj, NULL); struct hstate *h = kobj_to_hstate(kobj, NULL);
if (h->order >= MAX_ORDER)
return -EINVAL;
err = strict_strtoul(buf, 10, &input); err = strict_strtoul(buf, 10, &input);
if (err) if (err)
return 0; return 0;
...@@ -1864,6 +1877,9 @@ static int hugetlb_sysctl_handler_common(bool obey_mempolicy, ...@@ -1864,6 +1877,9 @@ static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
if (!write) if (!write)
tmp = h->max_huge_pages; tmp = h->max_huge_pages;
if (write && h->order >= MAX_ORDER)
return -EINVAL;
table->data = &tmp; table->data = &tmp;
table->maxlen = sizeof(unsigned long); table->maxlen = sizeof(unsigned long);
ret = proc_doulongvec_minmax(table, write, buffer, length, ppos); ret = proc_doulongvec_minmax(table, write, buffer, length, ppos);
...@@ -1927,6 +1943,9 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write, ...@@ -1927,6 +1943,9 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write,
if (!write) if (!write)
tmp = h->nr_overcommit_huge_pages; tmp = h->nr_overcommit_huge_pages;
if (write && h->order >= MAX_ORDER)
return -EINVAL;
table->data = &tmp; table->data = &tmp;
table->maxlen = sizeof(unsigned long); table->maxlen = sizeof(unsigned long);
ret = proc_doulongvec_minmax(table, write, buffer, length, ppos); ret = proc_doulongvec_minmax(table, write, buffer, length, ppos);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment