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 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 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 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 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 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 130 void __init hugetlb_sysctl_init(void) 131 { 132 register_sysctl_init("vm", hugetlb_table); 133 } 134 #endif /* CONFIG_SYSCTL */ 135