xref: /linux/mm/hugetlb_sysctl.c (revision 7203ca412fc8e8a0588e9adc0f777d3163f8dff3)
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