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
proc_hugetlb_doulongvec_minmax(const struct ctl_table * table,int write,void * buffer,size_t * length,loff_t * ppos,unsigned long * out)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
hugetlb_sysctl_handler_common(bool obey_mempolicy,const struct ctl_table * table,int write,void * buffer,size_t * length,loff_t * ppos)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
hugetlb_sysctl_handler(const struct ctl_table * table,int write,void * buffer,size_t * length,loff_t * ppos)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
hugetlb_mempolicy_sysctl_handler(const struct ctl_table * table,int write,void * buffer,size_t * length,loff_t * ppos)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
hugetlb_overcommit_handler(const struct ctl_table * table,int write,void * buffer,size_t * length,loff_t * ppos)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
hugetlb_sysctl_init(void)141 void __init hugetlb_sysctl_init(void)
142 {
143 register_sysctl_init("vm", hugetlb_table);
144 }
145 #endif /* CONFIG_SYSCTL */
146