diff options
author | Nishanth Aravamudan <nacc@us.ibm.com> | 2008-02-14 02:03:19 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-14 03:21:18 +0300 |
commit | 064d9efe947542097be669581f82d6b097e81d1a (patch) | |
tree | ddfc9f1c4d60135a7d7a1c5ebb7d0e85f683cfcb | |
parent | 2695a14d315c014474ccadbaed40b0169b00cb5b (diff) | |
download | linux-064d9efe947542097be669581f82d6b097e81d1a.tar.xz |
hugetlb: fix overcommit locking
proc_doulongvec_minmax() calls copy_to_user()/copy_from_user(), so we can't
hold hugetlb_lock over the call. Use a dummy variable to store the sysctl
result, like in hugetlb_sysctl_handler(), then grab the lock to update
nr_overcommit_huge_pages.
Signed-off-by: Nishanth Aravamudan <nacc@us.ibm.com>
Reported-by: Miles Lane <miles.lane@gmail.com>
Cc: Adam Litke <agl@us.ibm.com>
Cc: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/hugetlb.h | 2 | ||||
-rw-r--r-- | kernel/sysctl.c | 4 | ||||
-rw-r--r-- | mm/hugetlb.c | 6 |
3 files changed, 7 insertions, 5 deletions
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 7ca198b379af..addca4cd4f11 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -33,8 +33,8 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to); void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed); extern unsigned long max_huge_pages; +extern unsigned long sysctl_overcommit_huge_pages; extern unsigned long hugepages_treat_as_movable; -extern unsigned long nr_overcommit_huge_pages; extern const unsigned long hugetlb_zero, hugetlb_infinity; extern int sysctl_hugetlb_shm_group; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 924c674b76ea..8b7e95411795 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -978,8 +978,8 @@ static struct ctl_table vm_table[] = { { .ctl_name = CTL_UNNUMBERED, .procname = "nr_overcommit_hugepages", - .data = &nr_overcommit_huge_pages, - .maxlen = sizeof(nr_overcommit_huge_pages), + .data = &sysctl_overcommit_huge_pages, + .maxlen = sizeof(sysctl_overcommit_huge_pages), .mode = 0644, .proc_handler = &hugetlb_overcommit_handler, }, diff --git a/mm/hugetlb.c b/mm/hugetlb.c index d9a380312467..cb1b3a7ecdfc 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -24,14 +24,15 @@ const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL; static unsigned long nr_huge_pages, free_huge_pages, resv_huge_pages; static unsigned long surplus_huge_pages; +static unsigned long nr_overcommit_huge_pages; unsigned long max_huge_pages; +unsigned long sysctl_overcommit_huge_pages; static struct list_head hugepage_freelists[MAX_NUMNODES]; static unsigned int nr_huge_pages_node[MAX_NUMNODES]; static unsigned int free_huge_pages_node[MAX_NUMNODES]; static unsigned int surplus_huge_pages_node[MAX_NUMNODES]; static gfp_t htlb_alloc_mask = GFP_HIGHUSER; unsigned long hugepages_treat_as_movable; -unsigned long nr_overcommit_huge_pages; static int hugetlb_next_nid; /* @@ -609,8 +610,9 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write, struct file *file, void __user *buffer, size_t *length, loff_t *ppos) { - spin_lock(&hugetlb_lock); proc_doulongvec_minmax(table, write, file, buffer, length, ppos); + spin_lock(&hugetlb_lock); + nr_overcommit_huge_pages = sysctl_overcommit_huge_pages; spin_unlock(&hugetlb_lock); return 0; } |