xref: /linux/mm/hugetlb_sysctl.c (revision 6aacab308a5dfd222b2d23662bbae60c11007cfb)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * HugeTLB sysfs interfaces.
4  * (C) Nadia Yvette Chambers, April 2004
5  */
6 
7 #include <linux/sysctl.h>
8 
9 #include "hugetlb_internal.h"
10 
11 int movable_gigantic_pages;
12 
13 #ifdef CONFIG_SYSCTL
14 static int proc_hugetlb_doulongvec_minmax(const struct ctl_table *table, int write,
15 					  void *buffer, size_t *length,
16 					  loff_t *ppos, unsigned long *out)
17 {
18 	struct ctl_table dup_table;
19 
20 	/*
21 	 * In order to avoid races with __do_proc_doulongvec_minmax(), we
22 	 * can duplicate the @table and alter the duplicate of it.
23 	 */
24 	dup_table = *table;
25 	dup_table.data = out;
26 
27 	return proc_doulongvec_minmax(&dup_table, write, buffer, length, ppos);
28 }
29 
30 static int hugetlb_sysctl_handler_common(bool obey_mempolicy,
31 			 const struct ctl_table *table, int write,
32 			 void *buffer, size_t *length, loff_t *ppos)
33 {
34 	struct hstate *h = &default_hstate;
35 	unsigned long tmp = h->max_huge_pages;
36 	int ret;
37 
38 	if (!hugepages_supported())
39 		return -EOPNOTSUPP;
40 
41 	ret = proc_hugetlb_doulongvec_minmax(table, write, buffer, length, ppos,
42 					     &tmp);
43 	if (ret)
44 		goto out;
45 
46 	if (write)
47 		ret = __nr_hugepages_store_common(obey_mempolicy, h,
48 						  NUMA_NO_NODE, tmp, *length);
49 out:
50 	return ret;
51 }
52 
53 static int hugetlb_sysctl_handler(const struct ctl_table *table, int write,
54 			  void *buffer, size_t *length, loff_t *ppos)
55 {
56 
57 	return hugetlb_sysctl_handler_common(false, table, write,
58 							buffer, length, ppos);
59 }
60 
61 #ifdef CONFIG_NUMA
62 static int hugetlb_mempolicy_sysctl_handler(const struct ctl_table *table, int write,
63 			  void *buffer, size_t *length, loff_t *ppos)
64 {
65 	return hugetlb_sysctl_handler_common(true, table, write,
66 							buffer, length, ppos);
67 }
68 #endif /* CONFIG_NUMA */
69 
70 static int hugetlb_overcommit_handler(const struct ctl_table *table, int write,
71 		void *buffer, size_t *length, loff_t *ppos)
72 {
73 	struct hstate *h = &default_hstate;
74 	unsigned long tmp;
75 	int ret;
76 
77 	if (!hugepages_supported())
78 		return -EOPNOTSUPP;
79 
80 	tmp = h->nr_overcommit_huge_pages;
81 
82 	if (write && hstate_is_gigantic_no_runtime(h))
83 		return -EINVAL;
84 
85 	ret = proc_hugetlb_doulongvec_minmax(table, write, buffer, length, ppos,
86 					     &tmp);
87 	if (ret)
88 		goto out;
89 
90 	if (write) {
91 		spin_lock_irq(&hugetlb_lock);
92 		h->nr_overcommit_huge_pages = tmp;
93 		spin_unlock_irq(&hugetlb_lock);
94 	}
95 out:
96 	return ret;
97 }
98 
99 static const struct ctl_table hugetlb_table[] = {
100 	{
101 		.procname	= "nr_hugepages",
102 		.data		= NULL,
103 		.maxlen		= sizeof(unsigned long),
104 		.mode		= 0644,
105 		.proc_handler	= hugetlb_sysctl_handler,
106 	},
107 #ifdef CONFIG_NUMA
108 	{
109 		.procname       = "nr_hugepages_mempolicy",
110 		.data           = NULL,
111 		.maxlen         = sizeof(unsigned long),
112 		.mode           = 0644,
113 		.proc_handler   = &hugetlb_mempolicy_sysctl_handler,
114 	},
115 #endif
116 	{
117 		.procname	= "hugetlb_shm_group",
118 		.data		= &sysctl_hugetlb_shm_group,
119 		.maxlen		= sizeof(gid_t),
120 		.mode		= 0644,
121 		.proc_handler	= proc_dointvec,
122 	},
123 	{
124 		.procname	= "nr_overcommit_hugepages",
125 		.data		= NULL,
126 		.maxlen		= sizeof(unsigned long),
127 		.mode		= 0644,
128 		.proc_handler	= hugetlb_overcommit_handler,
129 	},
130 #ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION
131 	{
132 		.procname	= "movable_gigantic_pages",
133 		.data		= &movable_gigantic_pages,
134 		.maxlen		= sizeof(int),
135 		.mode		= 0644,
136 		.proc_handler	= proc_dointvec,
137 	},
138 #endif
139 };
140 
141 void __init hugetlb_sysctl_init(void)
142 {
143 	register_sysctl_init("vm", hugetlb_table);
144 }
145 #endif /* CONFIG_SYSCTL */
146