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