summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-08-20 08:46:41 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2026-08-20 08:46:41 -0700
commit9d2ed026f031f764e9450ac9aada2f46bc977397 (patch)
tree62f07957703256ec389c3975269b0c7127afcf77
parent91ec2035134982b98fab0609a9fd8480e8217dc1 (diff)
parent8d75c338f0bcecaa6c9af67f86c176b67b6acf3e (diff)
Merge tag 'sysctl-7.03-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl
Pull sysctl updates from Joel Granados: - Fix kernel-doc warnings by adjusting in file documentation - Consolidate do_proc_* function into do_proc_vec Consolidate three slightly different implementations of applying a converter on all elements of a vector. Fixes to this function now propagate to the three types. - Replace CONFIG_PROC_SYSCTL with CONFIG_SYSCTL (they were the same) and restrict cad_pid modifications to global root (GLOBAL_ROOT_UID) * tag 'sysctl-7.03-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl: sysctl: remove CONFIG_PROC_SYSCTL, it just mirrors CONFIG_SYSCTL sysctl: move the "cad_pid" entry from pid_table[] to kern_reboot_table[] sysctl: repair some kernel-doc comments sysctl: add Returns: kernel-doc for all functions sysctl: Update API function documentation sysctl: Rename proc_doulongvec_minmax_conv to proc_doulongvec_conv sysctl: Group proc_handler declarations and document sysctl: Replace do_proc_do{int,ulong,uint}vec with do_proc_vec sysctl: Add negp parameter to douintvec converter functions sysctl: Move default converter assignment out of do_proc_dointvec
-rw-r--r--arch/m68k/configs/amcore_defconfig2
-rw-r--r--arch/m68k/configs/stmark2_defconfig2
-rw-r--r--arch/s390/Kconfig4
-rw-r--r--arch/x86/kernel/cpu/bus_lock.c2
-rw-r--r--fs/pipe.c2
-rw-r--r--fs/proc/Kconfig3
-rw-r--r--fs/proc/Makefile2
-rw-r--r--fs/proc/internal.h2
-rw-r--r--include/linux/sysctl.h131
-rw-r--r--include/linux/utsname.h2
-rw-r--r--init/Kconfig3
-rw-r--r--kernel/delayacct.c2
-rw-r--r--kernel/pid.c31
-rw-r--r--kernel/reboot.c29
-rw-r--r--kernel/sched/core.c8
-rw-r--r--kernel/sched/topology.c4
-rw-r--r--kernel/sysctl.c528
-rw-r--r--kernel/time/jiffies.c31
-rw-r--r--kernel/utsname_sysctl.c4
-rw-r--r--lib/Kconfig.debug2
-rw-r--r--lib/test_sysctl.c2
-rw-r--r--net/mpls/Kconfig2
-rw-r--r--tools/testing/selftests/net/config2
-rw-r--r--tools/testing/selftests/net/packetdrill/config2
-rw-r--r--tools/testing/selftests/wireguard/qemu/kernel.config2
25 files changed, 451 insertions, 353 deletions
diff --git a/arch/m68k/configs/amcore_defconfig b/arch/m68k/configs/amcore_defconfig
index f310b5dacfd8..49f1de51d87e 100644
--- a/arch/m68k/configs/amcore_defconfig
+++ b/arch/m68k/configs/amcore_defconfig
@@ -74,7 +74,7 @@ CONFIG_RTC_DRV_DS1307=y
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY_USER is not set
CONFIG_FSCACHE=y
-# CONFIG_PROC_SYSCTL is not set
+# CONFIG_SYSCTL is not set
CONFIG_JFFS2_FS=y
CONFIG_ROMFS_FS=y
CONFIG_ROMFS_BACKED_BY_BOTH=y
diff --git a/arch/m68k/configs/stmark2_defconfig b/arch/m68k/configs/stmark2_defconfig
index b3fb95f73a95..cd454369bfe8 100644
--- a/arch/m68k/configs/stmark2_defconfig
+++ b/arch/m68k/configs/stmark2_defconfig
@@ -87,7 +87,7 @@ CONFIG_EXT4_FS_SECURITY=y
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY_USER is not set
CONFIG_OVERLAY_FS=y
-# CONFIG_PROC_SYSCTL is not set
+# CONFIG_SYSCTL is not set
CONFIG_SQUASHFS=y
CONFIG_XZ_DEC=y
CONFIG_PRINTK_TIME=y
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index b6aa74480a25..e7d2b42ae02e 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -575,7 +575,7 @@ config HIPERDISPATCH_ON
def_bool y
bool "Use hiperdispatch on vertical polarization by default"
depends on SCHED_TOPOLOGY
- depends on PROC_SYSCTL
+ depends on SYSCTL
help
Hiperdispatch aims to improve the CPU scheduler's decision
making when using vertical polarization by adjusting CPU
@@ -893,7 +893,7 @@ config CMM_IUCV
config APPLDATA_BASE
def_bool n
prompt "Linux - VM Monitor Stream, base infrastructure"
- depends on PROC_SYSCTL
+ depends on SYSCTL
help
This provides a kernel interface for creating and updating z/VM APPLDATA
monitor records. The monitor records are updated at certain time
diff --git a/arch/x86/kernel/cpu/bus_lock.c b/arch/x86/kernel/cpu/bus_lock.c
index bba28607a59a..177f964d4d36 100644
--- a/arch/x86/kernel/cpu/bus_lock.c
+++ b/arch/x86/kernel/cpu/bus_lock.c
@@ -50,7 +50,7 @@ static struct ratelimit_state bld_ratelimit;
static unsigned int sysctl_sld_mitigate = 1;
static DEFINE_SEMAPHORE(buslock_sem, 1);
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
static const struct ctl_table sld_sysctls[] = {
{
.procname = "split_lock_mitigate",
diff --git a/fs/pipe.c b/fs/pipe.c
index 0c77191a050c..292425a834dd 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1572,7 +1572,7 @@ static int u2k_pipe_maxsz(const ulong *u_ptr, uint *k_ptr)
return proc_uint_u2k_conv_uop(u_ptr, k_ptr, round_pipe_size_ul);
}
-static int do_proc_uint_conv_pipe_maxsz(ulong *u_ptr, uint *k_ptr,
+static int do_proc_uint_conv_pipe_maxsz(bool *negp, ulong *u_ptr, uint *k_ptr,
int dir, const struct ctl_table *table)
{
return proc_uint_conv(u_ptr, k_ptr, dir, table, true,
diff --git a/fs/proc/Kconfig b/fs/proc/Kconfig
index 6ae966c561e7..24f5a36f45df 100644
--- a/fs/proc/Kconfig
+++ b/fs/proc/Kconfig
@@ -80,10 +80,9 @@ config PROC_VMCORE_DEVICE_RAM
Relevant architectures should select NEED_PROC_VMCORE_DEVICE_RAM.
-config PROC_SYSCTL
+config SYSCTL
bool "Sysctl support (/proc/sys)" if EXPERT
depends on PROC_FS
- select SYSCTL
default y
help
The sysctl interface provides a means of dynamically changing
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 8bc615ff84e5..27e2b26b2d42 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -29,7 +29,7 @@ proc-y += softirqs.o
proc-y += namespaces.o
proc-y += self.o
proc-y += thread_self.o
-proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o
+proc-$(CONFIG_SYSCTL) += proc_sysctl.o
proc-$(CONFIG_NET) += proc_net.o
proc-$(CONFIG_PROC_KCORE) += kcore.o
proc-$(CONFIG_PROC_VMCORE) += vmcore.o
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index b232e1098117..04bd6c9e65a7 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -351,7 +351,7 @@ extern void proc_thread_self_init(void);
/*
* proc_sysctl.c
*/
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
extern int proc_sys_init(void);
extern void proc_sys_evict_inode(struct inode *inode,
struct ctl_table_header *head);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 2886fbceb5d6..e5d7226ab6f5 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -59,7 +59,7 @@ extern const int sysctl_vals[];
#define SYSCTL_LONG_ONE ((void *)&sysctl_long_vals[1])
#define SYSCTL_LONG_MAX ((void *)&sysctl_long_vals[2])
-/**
+/*
*
* "dir" originates from read_iter (dir = 0) or write_iter (dir = 1)
* in the file_operations struct at proc/proc_sysctl.c. Its value means
@@ -74,53 +74,108 @@ extern const int sysctl_vals[];
extern const unsigned long sysctl_long_vals[];
-typedef int proc_handler(const struct ctl_table *ctl, int write, void *buffer,
- size_t *lenp, loff_t *ppos);
-
-int proc_dostring(const struct ctl_table *, int, void *, size_t *, loff_t *);
-int proc_dobool(const struct ctl_table *table, int write, void *buffer,
- size_t *lenp, loff_t *ppos);
+typedef int proc_handler(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
-int proc_dointvec(const struct ctl_table *, int, void *, size_t *, loff_t *);
-int proc_dointvec_minmax(const struct ctl_table *table, int dir, void *buffer,
+/* proc_handler functions */
+int proc_dostring(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp,
+ loff_t *ppos);
+int proc_dobool(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp,
+ loff_t *ppos);
+int proc_dointvec(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp,
+ loff_t *ppos);
+int proc_dointvec_minmax(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
+int proc_douintvec(const struct ctl_table *ctl, int dir, void *buf, size_t *lenp,
+ loff_t *ppos);
+int proc_douintvec_minmax(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
+int proc_dou8vec_minmax(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
+int proc_doulongvec_minmax(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
+int proc_do_large_bitmap(const struct ctl_table *ctl, int dir, void *buf,
size_t *lenp, loff_t *ppos);
-int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer,
+int proc_do_static_key(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos);
+
+/*
+ * proc_handler aggregators
+ *
+ * Create a proc_handler with a custom converter. Use when the user space
+ * value is a transformation of the kernel value. Cannot be passed as
+ * proc_handlers.
+ *
+ * Example of creating your custom proc handler:
+ * int custom_converter(bool *negp, ulong *u_ptr, uint *k_ptr,
+ * int dir, const struct ctl_table *ctl) {...}
+ * int custom_proc_handler(const struct ctl_table *ctl, int dir,
+ * void *buf, size_t *lenp, loff_t *ppos
+ * { return proc_dointvec_conv(ctl, dir, buf, lenp, ppos, custom_converter); }
+ */
+int proc_dointvec_conv(const struct ctl_table *ctl, int dir, void *buf,
size_t *lenp, loff_t *ppos,
int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr,
- int dir, const struct ctl_table *table));
-int proc_int_k2u_conv_kop(ulong *u_ptr, const int *k_ptr, bool *negp,
- ulong (*k_ptr_op)(const ulong));
-int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp,
- ulong (*u_ptr_op)(const ulong));
+ int dir, const struct ctl_table *ctl));
+int proc_douintvec_conv(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos,
+ int (*conv)(bool *negp, ulong *u_ptr, uint *k_ptr,
+ int dir, const struct ctl_table *ctl));
+int proc_doulongvec_conv(const struct ctl_table *ctl, int dir, void *buf,
+ size_t *lenp, loff_t *ppos,
+ int (*conv)(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *ctl));
+
+/*
+ * bi-directional converter functions
+ *
+ * Specify the converter function for both directions (user to kernel & kernel
+ * to user). Use when you want to change the value of the variable before
+ * assignment. Used to create custom proc_handler aggregators.
+ *
+ * Example of creating your custom bi-directional converter:
+ * int custom_u2k(ulong *u_ptr, const uint *k_ptr) { ... }
+ * int custom_converter(bool *negp, ulong *u_ptr, uint *k_ptr,
+ * int dir, const struct ctl_table *ctl)
+ * { return proc_uint_conv(u_ptr, k_ptr, dir, ctl, true,
+ * custom_u2k, proc_uint_k2u_conv}
+ */
int proc_int_conv(bool *negp, ulong *u_ptr, int *k_ptr, int dir,
const struct ctl_table *tbl, bool k_ptr_range_check,
int (*user_to_kern)(const bool *negp, const ulong *u_ptr, int *k_ptr),
int (*kern_to_user)(bool *negp, ulong *u_ptr, const int *k_ptr));
-
-int proc_douintvec(const struct ctl_table *, int, void *, size_t *, loff_t *);
-int proc_douintvec_minmax(const struct ctl_table *table, int write, void *buffer,
- size_t *lenp, loff_t *ppos);
-int proc_douintvec_conv(const struct ctl_table *table, int write, void *buffer,
- size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *lvalp, unsigned int *valp,
- int write, const struct ctl_table *table));
-int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr);
-int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,
- ulong (*u_ptr_op)(const ulong));
int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir,
const struct ctl_table *tbl, bool k_ptr_range_check,
int (*user_to_kern)(const ulong *u_ptr, uint *k_ptr),
int (*kern_to_user)(ulong *u_ptr, const uint *k_ptr));
+int proc_ulong_conv(ulong *u_ptr, ulong *k_ptr, int dir,
+ const struct ctl_table *tbl, bool k_ptr_range_check,
+ int (*user_to_kern)(const ulong *u_ptr, ulong *k_ptr),
+ int (*kern_to_user)(ulong *u_ptr, const ulong *k_ptr));
-int proc_dou8vec_minmax(const struct ctl_table *table, int write, void *buffer,
- size_t *lenp, loff_t *ppos);
-int proc_doulongvec_minmax(const struct ctl_table *, int, void *, size_t *, loff_t *);
-int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,
- void *buffer, size_t *lenp, loff_t *ppos,
- unsigned long convmul, unsigned long convdiv);
-int proc_do_large_bitmap(const struct ctl_table *, int, void *, size_t *, loff_t *);
-int proc_do_static_key(const struct ctl_table *table, int write, void *buffer,
- size_t *lenp, loff_t *ppos);
+/*
+ * uni-directional converter functions
+ *
+ * Specify the converter function for one directions (user to kernel or
+ * kernel to user). Use to call the actual value conversion. Used to Create
+ * bi-directional converters.
+ *
+ * Example of creating a uni-directional converter:
+ * ulong op(const ulong val) { ... }
+ * int custom_unidir_conv(ulong *u_ptr, const uint *k_ptr)
+ * { return proc_uint_k2u_conv_kop(u_ptr, k_ptr, op); }
+ */
+int proc_int_k2u_conv_kop(ulong *u_ptr, const int *k_ptr, bool *negp,
+ ulong (*k_ptr_op)(const ulong));
+int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp,
+ ulong (*u_ptr_op)(const ulong));
+int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr);
+int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,
+ ulong (*u_ptr_op)(const ulong));
+int proc_ulong_u2k_conv_uop(const ulong *u_ptr, ulong *k_ptr,
+ ulong (*u_ptr_op)(const ulong));
+int proc_ulong_k2u_conv_kop(ulong *u_ptr, const ulong *k_ptr,
+ ulong (*k_ptr_op)(const ulong));
/*
* Register a set of sysctl names by calling register_sysctl
@@ -190,9 +245,9 @@ struct ctl_node {
* @nreg: When nreg drops to 0 the ctl_table_header will be unregistered.
* @rcu: Delays the freeing of the inode. Introduced with "unfuck proc_sysctl ->d_compare()"
*
- * @type: Enumeration to differentiate between ctl target types
- * @type.SYSCTL_TABLE_TYPE_DEFAULT: ctl target with no special considerations
- * @type.SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY: Identifies a permanently empty dir
+ * @type: Enumeration to differentiate between ctl target types:
+ * type.SYSCTL_TABLE_TYPE_DEFAULT: ctl target with no special considerations
+ * type.SYSCTL_TABLE_TYPE_PERMANENTLY_EMPTY: Identifies a permanently empty dir
* target to serve as a mount point
*/
struct ctl_table_header {
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index 547bd4439706..dc5594ffffcc 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -18,7 +18,7 @@ enum uts_proc {
UTS_PROC_DOMAINNAME,
};
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
extern void uts_proc_notify(enum uts_proc proc);
#else
static inline void uts_proc_notify(enum uts_proc proc)
diff --git a/init/Kconfig b/init/Kconfig
index db9f72d2061c..60448fd4ee12 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1665,9 +1665,6 @@ config LD_ORPHAN_WARN_LEVEL
default "error" if WERROR
default "warn"
-config SYSCTL
- bool
-
config HAVE_UID16
bool
diff --git a/kernel/delayacct.c b/kernel/delayacct.c
index 2e55c493c98b..479e860aff70 100644
--- a/kernel/delayacct.c
+++ b/kernel/delayacct.c
@@ -54,7 +54,7 @@ void delayacct_init(void)
set_delayacct(delayacct_on);
}
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
static int sysctl_delayacct(const struct ctl_table *table, int write, void *buffer,
size_t *lenp, loff_t *ppos)
{
diff --git a/kernel/pid.c b/kernel/pid.c
index d01d0dd7114b..95b8ccfa8269 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -766,29 +766,6 @@ static struct ctl_table_root pid_table_root = {
.set_ownership = pid_table_root_set_ownership,
};
-static int proc_do_cad_pid(const struct ctl_table *table, int write, void *buffer,
- size_t *lenp, loff_t *ppos)
-{
- struct pid *new_pid;
- pid_t tmp_pid;
- int r;
- struct ctl_table tmp_table = *table;
-
- tmp_pid = pid_vnr(cad_pid);
- tmp_table.data = &tmp_pid;
-
- r = proc_dointvec(&tmp_table, write, buffer, lenp, ppos);
- if (r || !write)
- return r;
-
- new_pid = find_get_pid(tmp_pid);
- if (!new_pid)
- return -ESRCH;
-
- put_pid(xchg(&cad_pid, new_pid));
- return 0;
-}
-
static const struct ctl_table pid_table[] = {
{
.procname = "pid_max",
@@ -799,14 +776,6 @@ static const struct ctl_table pid_table[] = {
.extra1 = &pid_max_min,
.extra2 = &pid_max_max,
},
-#ifdef CONFIG_PROC_SYSCTL
- {
- .procname = "cad_pid",
- .maxlen = sizeof(int),
- .mode = 0600,
- .proc_handler = proc_do_cad_pid,
- },
-#endif
};
#endif
diff --git a/kernel/reboot.c b/kernel/reboot.c
index 695c33e75efd..f070c5c1103a 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -1366,6 +1366,29 @@ static struct attribute *reboot_attrs[] = {
};
#ifdef CONFIG_SYSCTL
+static int proc_do_cad_pid(const struct ctl_table *table, int write, void *buffer,
+ size_t *lenp, loff_t *ppos)
+{
+ struct ctl_table tmp_table = *table;
+ struct pid *new_pid;
+ pid_t tmp_pid;
+ int r;
+
+ tmp_pid = pid_vnr(cad_pid);
+ tmp_table.data = &tmp_pid;
+
+ r = proc_dointvec(&tmp_table, write, buffer, lenp, ppos);
+ if (r || !write)
+ return r;
+
+ new_pid = find_get_pid(tmp_pid);
+ if (!new_pid)
+ return -ESRCH;
+
+ put_pid(xchg(&cad_pid, new_pid));
+ return 0;
+}
+
static const struct ctl_table kern_reboot_table[] = {
{
.procname = "poweroff_cmd",
@@ -1381,6 +1404,12 @@ static const struct ctl_table kern_reboot_table[] = {
.mode = 0644,
.proc_handler = proc_dointvec,
},
+ {
+ .procname = "cad_pid",
+ .maxlen = sizeof(int),
+ .mode = 0600,
+ .proc_handler = proc_do_cad_pid,
+ },
};
static void __init kernel_reboot_sysctls_init(void)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index f5f7ff8c680a..6544e56925ee 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -4638,7 +4638,7 @@ void set_numabalancing_state(bool enabled)
__set_numabalancing_state(enabled);
}
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
static void reset_memory_tiering(void)
{
struct pglist_data *pgdat;
@@ -4674,7 +4674,7 @@ static int sysctl_numa_balancing(const struct ctl_table *table, int write,
}
return err;
}
-#endif /* CONFIG_PROC_SYSCTL */
+#endif /* CONFIG_SYSCTL */
#endif /* CONFIG_NUMA_BALANCING */
#ifdef CONFIG_SCHEDSTATS
@@ -4718,7 +4718,7 @@ out:
}
__setup("schedstats=", setup_schedstats);
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
static int sysctl_schedstats(const struct ctl_table *table, int write, void *buffer,
size_t *lenp, loff_t *ppos)
{
@@ -4738,7 +4738,7 @@ static int sysctl_schedstats(const struct ctl_table *table, int write, void *buf
set_schedstats(state);
return err;
}
-#endif /* CONFIG_PROC_SYSCTL */
+#endif /* CONFIG_SYSCTL */
#endif /* CONFIG_SCHEDSTATS */
#ifdef CONFIG_SYSCTL
diff --git a/kernel/sched/topology.c b/kernel/sched/topology.c
index 21e816ad23ee..0248227d983a 100644
--- a/kernel/sched/topology.c
+++ b/kernel/sched/topology.c
@@ -271,7 +271,7 @@ void rebuild_sched_domains_energy(void)
mutex_unlock(&sched_energy_mutex);
}
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
static int sched_energy_aware_handler(const struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
@@ -317,7 +317,7 @@ static int __init sched_energy_aware_sysctl_init(void)
}
late_initcall(sched_energy_aware_sysctl_init);
-#endif /* CONFIG_PROC_SYSCTL */
+#endif /* CONFIG_SYSCTL */
static void free_pd(struct perf_domain *pd)
{
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c9efb17cc255..f7b75985d542 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -35,7 +35,7 @@ EXPORT_SYMBOL_GPL(sysctl_long_vals);
static const int ngroups_max = NGROUPS_MAX;
static const int cap_last_cap = CAP_LAST_CAP;
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
/**
* enum sysctl_writes_mode - supported sysctl write modes
@@ -64,14 +64,14 @@ enum sysctl_writes_mode {
};
static enum sysctl_writes_mode sysctl_writes_strict = SYSCTL_WRITES_STRICT;
-#endif /* CONFIG_PROC_SYSCTL */
+#endif /* CONFIG_SYSCTL */
#endif /* CONFIG_SYSCTL */
/*
* /proc/sys support
*/
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
static int _proc_do_string(char *data, int maxlen, int dir,
char *buffer, size_t *lenp, loff_t *ppos)
@@ -148,7 +148,7 @@ static void warn_sysctl_write(const struct ctl_table *table)
* @ppos: file position
* @table: the sysctl table
*
- * Returns true if the first position is non-zero and the sysctl_writes_strict
+ * Returns: true if the first position is non-zero and the sysctl_writes_strict
* mode indicates this is not allowed for numeric input types. String proc
* handlers can ignore the return value.
*/
@@ -184,7 +184,7 @@ static bool proc_first_pos_non_zero_ignore(loff_t *ppos,
* and a newline '\n' is added. It is truncated if the buffer is
* not large enough.
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_dostring(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
@@ -225,11 +225,14 @@ static void proc_skip_char(char **buf, size_t *size, const char v)
* @base: the base to use
* @res: where the parsed integer will be stored
*
- * In case of success 0 is returned and @res will contain the parsed integer,
- * @endp will hold any trailing characters.
* This function will fail the parse on overflow. If there wasn't an overflow
* the function will defer the decision what characters count as invalid to the
* caller.
+ *
+ * Returns:
+ * * %0 on success and @res will contain the parsed integer,
+ * @endp will hold any trailing characters.
+ * * %-ERANGE on overflow.
*/
static int strtoul_lenient(const char *cp, char **endp, unsigned int base,
unsigned long *res)
@@ -263,10 +266,12 @@ static int strtoul_lenient(const char *cp, char **endp, unsigned int base,
* @perm_tr_len: size of the perm_tr vector
* @tr: pointer to store the trailer character
*
- * In case of success %0 is returned and @buf and @size are updated with
- * the amount of bytes read. If @tr is non-NULL and a trailing
- * character exists (size is non-zero after returning from this
- * function), @tr is updated with the trailing character.
+ * Returns:
+ * * %0 on success and @buf and @size are updated with
+ * the amount of bytes read. If @tr is non-NULL and a trailing
+ * character exists (size is non-zero after returning from this
+ * function), @tr is updated with the trailing character.
+ * * %-EINVAL on failure.
*/
static int proc_get_long(char **buf, size_t *size,
unsigned long *val, bool *neg,
@@ -365,7 +370,7 @@ static void proc_put_char(void **buf, size_t *size, char c)
* not NULL. Check that the values are less than UINT_MAX to avoid
* having to support wrap around from userspace.
*
- * returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,
ulong (*u_ptr_op)(const ulong))
@@ -386,7 +391,7 @@ int proc_uint_u2k_conv_uop(const ulong *u_ptr, uint *k_ptr,
*
* Uses READ_ONCE to assign value to u_ptr.
*
- * returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr)
{
@@ -409,7 +414,7 @@ int proc_uint_k2u_conv(ulong *u_ptr, const uint *k_ptr)
* When direction is kernel to user, then the u_ptr is modified.
* When direction is user to kernel, then the k_ptr is modified.
*
- * Returns 0 on success
+ * Returns: %0 on success
*/
int proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir,
const struct ctl_table *tbl, bool k_ptr_range_check,
@@ -444,15 +449,15 @@ static int proc_uint_u2k_conv(const ulong *u_ptr, uint *k_ptr)
return proc_uint_u2k_conv_uop(u_ptr, k_ptr, NULL);
}
-static int do_proc_uint_conv(ulong *u_ptr, uint *k_ptr, int dir,
+static int do_proc_uint_conv(bool *negp, ulong *u_ptr, uint *k_ptr, int dir,
const struct ctl_table *tbl)
{
return proc_uint_conv(u_ptr, k_ptr, dir, tbl, false,
proc_uint_u2k_conv, proc_uint_k2u_conv);
}
-static int do_proc_uint_conv_minmax(ulong *u_ptr, uint *k_ptr, int dir,
- const struct ctl_table *tbl)
+static int do_proc_uint_conv_minmax(bool *negp, ulong *u_ptr, uint *k_ptr,
+ int dir, const struct ctl_table *tbl)
{
return proc_uint_conv(u_ptr, k_ptr, dir, tbl, true,
proc_uint_u2k_conv, proc_uint_k2u_conv);
@@ -515,6 +520,23 @@ int proc_int_u2k_conv_uop(const ulong *u_ptr, int *k_ptr, const bool *negp,
return 0;
}
+/**
+ * proc_int_conv - Change user or kernel pointer based on direction
+ *
+ * @negp: will be passed to uni-directional converters
+ * @u_ptr: pointer to user variable
+ * @k_ptr: pointer to kernel variable
+ * @dir: %TRUE if this is a write to the sysctl file
+ * @tbl: the sysctl table
+ * @k_ptr_range_check: Check range for k_ptr when %TRUE
+ * @user_to_kern: Callback used to assign value from user to kernel var
+ * @kern_to_user: Callback used to assign value from kernel to user var
+ *
+ * When direction is kernel to user, then the u_ptr is modified.
+ * When direction is user to kernel, then the k_ptr is modified.
+ *
+ * Returns: 0 on success
+ */
int proc_int_conv(bool *negp, ulong *u_ptr, int *k_ptr, int dir,
const struct ctl_table *tbl, bool k_ptr_range_check,
int (*user_to_kern)(const bool *negp, const ulong *u_ptr, int *k_ptr),
@@ -572,14 +594,80 @@ static int do_proc_int_conv_minmax(bool *negp, unsigned long *u_ptr, int *k_ptr,
static const char proc_wspace_sep[] = { ' ', '\t', '\n' };
-static int do_proc_dointvec(const struct ctl_table *table, int dir,
- void *buffer, size_t *lenp, loff_t *ppos,
- int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr,
- int dir, const struct ctl_table *table))
+/*
+ * Element type processed by do_proc_vec(). The tag selects the element size
+ * and signedness, and it selects which member of union proc_vec_conv is live.
+ */
+enum proc_vec_type {
+ PROC_VEC_INT,
+ PROC_VEC_UINT,
+ PROC_VEC_ULONG,
+};
+
+/*
+ * Converter passed to do_proc_vec(). Only the member matching the
+ * enum proc_vec_type tag is ever read, so every dispatch stays fully typed and
+ * no void * converter pointer is needed.
+ */
+union proc_vec_conv {
+ int (*int_conv)(bool *negp, ulong *u_ptr, int *k_ptr,
+ int dir, const struct ctl_table *table);
+ int (*uint_conv)(bool *negp, ulong *u_ptr, uint *k_ptr,
+ int dir, const struct ctl_table *table);
+ int (*ulong_conv)(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *table);
+};
+
+/*
+ * Dispatch to the converter member selected by @type. @k_ptr walks
+ * table->data as raw bytes and is cast back to the element type here.
+ */
+static int proc_vec_conv(enum proc_vec_type type, union proc_vec_conv conv,
+ bool *negp, ulong *u_ptr, char *k_ptr, int dir,
+ const struct ctl_table *table)
+{
+ switch (type) {
+ case PROC_VEC_INT:
+ return conv.int_conv(negp, u_ptr, (int *)k_ptr, dir, table);
+ case PROC_VEC_UINT:
+ return conv.uint_conv(negp, u_ptr, (uint *)k_ptr, dir, table);
+ case PROC_VEC_ULONG:
+ return conv.ulong_conv(negp, u_ptr, (ulong *)k_ptr, dir, table);
+ }
+ return -EINVAL;
+}
+
+/*
+ * Read/write a vector of @type elements. The element size and signedness are
+ * derived from @type, so a single runtime function replaces the per-type
+ * variants. table->data is walked as raw bytes (@i) advanced by @size; the
+ * converter performs the actual typed load/store.
+ */
+static int do_proc_vec(const struct ctl_table *table, int dir,
+ void *buffer, size_t *lenp, loff_t *ppos,
+ enum proc_vec_type type, union proc_vec_conv conv)
{
- int *i, vleft, first = 1, err = 0;
- size_t left;
- char *p;
+ int vleft, first = 1, err = 0;
+ size_t left, size;
+ bool is_unsigned;
+ char *i, *p;
+
+ switch (type) {
+ case PROC_VEC_INT:
+ size = sizeof(int);
+ is_unsigned = false;
+ break;
+ case PROC_VEC_UINT:
+ size = sizeof(uint);
+ is_unsigned = true;
+ break;
+ case PROC_VEC_ULONG:
+ size = sizeof(ulong);
+ is_unsigned = true;
+ break;
+ default:
+ return -EINVAL;
+ }
if (!table->data || !table->maxlen || !*lenp ||
(*ppos && SYSCTL_KERN_TO_USER(dir))) {
@@ -587,12 +675,13 @@ static int do_proc_dointvec(const struct ctl_table *table, int dir,
return 0;
}
- i = (int *) table->data;
- vleft = table->maxlen / sizeof(*i);
+ i = table->data;
+ vleft = table->maxlen / size;
left = *lenp;
- if (!conv)
- conv = do_proc_int_conv;
+ /* uint arrays are not supported, *Do not* add support for them. */
+ if (type == PROC_VEC_UINT && vleft != 1)
+ return -EINVAL;
if (SYSCTL_USER_TO_KERN(dir)) {
if (proc_first_pos_non_zero_ignore(ppos, table))
@@ -603,9 +692,9 @@ static int do_proc_dointvec(const struct ctl_table *table, int dir,
p = buffer;
}
- for (; left && vleft--; i++, first=0) {
+ for (; left && vleft--; i += size, first = 0) {
unsigned long lval;
- bool neg;
+ bool neg = false;
if (SYSCTL_USER_TO_KERN(dir)) {
proc_skip_spaces(&p, &left);
@@ -613,16 +702,18 @@ static int do_proc_dointvec(const struct ctl_table *table, int dir,
if (!left)
break;
err = proc_get_long(&p, &left, &lval, &neg,
- proc_wspace_sep,
- sizeof(proc_wspace_sep), NULL);
+ proc_wspace_sep,
+ sizeof(proc_wspace_sep), NULL);
+ if (!err && neg && is_unsigned)
+ err = -EINVAL;
if (err)
break;
- if (conv(&neg, &lval, i, 1, table)) {
+ if (proc_vec_conv(type, conv, &neg, &lval, i, dir, table)) {
err = -EINVAL;
break;
}
} else {
- if (conv(&neg, &lval, i, 0, table)) {
+ if (proc_vec_conv(type, conv, &neg, &lval, i, dir, table)) {
err = -EINVAL;
break;
}
@@ -644,122 +735,6 @@ out:
return err;
}
-static int do_proc_douintvec_w(const struct ctl_table *table, void *buffer,
- size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *u_ptr,
- unsigned int *k_ptr, int dir,
- const struct ctl_table *table))
-{
- unsigned long lval;
- int err = 0;
- size_t left;
- bool neg;
- char *p = buffer;
-
- left = *lenp;
-
- if (proc_first_pos_non_zero_ignore(ppos, table))
- goto bail_early;
-
- if (left > PAGE_SIZE - 1)
- left = PAGE_SIZE - 1;
-
- proc_skip_spaces(&p, &left);
- if (!left) {
- err = -EINVAL;
- goto out_free;
- }
-
- err = proc_get_long(&p, &left, &lval, &neg,
- proc_wspace_sep,
- sizeof(proc_wspace_sep), NULL);
- if (err || neg) {
- err = -EINVAL;
- goto out_free;
- }
-
- if (conv(&lval, (unsigned int *) table->data, 1, table)) {
- err = -EINVAL;
- goto out_free;
- }
-
- if (!err && left)
- proc_skip_spaces(&p, &left);
-
-out_free:
- if (err)
- return -EINVAL;
-
- return 0;
-
-bail_early:
- *ppos += *lenp;
- return err;
-}
-
-static int do_proc_douintvec_r(const struct ctl_table *table, void *buffer,
- size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *u_ptr,
- unsigned int *k_ptr, int dir,
- const struct ctl_table *table))
-{
- unsigned long lval;
- int err = 0;
- size_t left;
-
- left = *lenp;
-
- if (conv(&lval, (unsigned int *) table->data, 0, table)) {
- err = -EINVAL;
- goto out;
- }
-
- proc_put_long(&buffer, &left, lval, false);
- if (!left)
- goto out;
-
- proc_put_char(&buffer, &left, '\n');
-
-out:
- *lenp -= left;
- *ppos += *lenp;
-
- return err;
-}
-
-static int do_proc_douintvec(const struct ctl_table *table, int dir,
- void *buffer, size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *u_ptr,
- unsigned int *k_ptr, int dir,
- const struct ctl_table *table))
-{
- unsigned int vleft;
-
- if (!table->data || !table->maxlen || !*lenp ||
- (*ppos && SYSCTL_KERN_TO_USER(dir))) {
- *lenp = 0;
- return 0;
- }
-
- vleft = table->maxlen / sizeof(unsigned int);
-
- /*
- * Arrays are not supported, keep this simple. *Do not* add
- * support for them.
- */
- if (vleft != 1) {
- *lenp = 0;
- return -EINVAL;
- }
-
- if (!conv)
- conv = do_proc_uint_conv;
-
- if (SYSCTL_USER_TO_KERN(dir))
- return do_proc_douintvec_w(table, buffer, lenp, ppos, conv);
- return do_proc_douintvec_r(table, buffer, lenp, ppos, conv);
-}
-
/**
* proc_douintvec_conv - read a vector of unsigned ints with a custom converter
*
@@ -774,14 +749,19 @@ static int do_proc_douintvec(const struct ctl_table *table, int dir,
* values from/to the user buffer, treated as an ASCII string. Negative
* strings are not allowed.
*
- * Returns 0 on success
+ * Returns: %0 on success
*/
int proc_douintvec_conv(const struct ctl_table *table, int dir, void *buffer,
size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *u_ptr, unsigned int *k_ptr,
+ int (*conv)(bool *negp, ulong *u_ptr, uint *k_ptr,
int dir, const struct ctl_table *table))
{
- return do_proc_douintvec(table, dir, buffer, lenp, ppos, conv);
+
+ if (!conv)
+ conv = do_proc_uint_conv;
+
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_UINT,
+ (union proc_vec_conv){ .uint_conv = conv });
}
/**
@@ -798,7 +778,7 @@ int proc_douintvec_conv(const struct ctl_table *table, int dir, void *buffer,
* table->data must point to a bool variable and table->maxlen must
* be sizeof(bool).
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_dobool(const struct ctl_table *table, int dir, void *buffer,
size_t *lenp, loff_t *ppos)
@@ -835,12 +815,13 @@ int proc_dobool(const struct ctl_table *table, int dir, void *buffer,
* Reads/writes up to table->maxlen/sizeof(unsigned int) integer
* values from/to the user buffer, treated as an ASCII string.
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_dointvec(const struct ctl_table *table, int dir, void *buffer,
size_t *lenp, loff_t *ppos)
{
- return do_proc_dointvec(table, dir, buffer, lenp, ppos, NULL);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_INT,
+ (union proc_vec_conv){ .int_conv = do_proc_int_conv });
}
/**
@@ -854,13 +835,13 @@ int proc_dointvec(const struct ctl_table *table, int dir, void *buffer,
* Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer
* values from/to the user buffer, treated as an ASCII string.
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_douintvec(const struct ctl_table *table, int dir, void *buffer,
size_t *lenp, loff_t *ppos)
{
- return do_proc_douintvec(table, dir, buffer, lenp, ppos,
- do_proc_uint_conv);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_UINT,
+ (union proc_vec_conv){ .uint_conv = do_proc_uint_conv });
}
/**
@@ -877,14 +858,14 @@ int proc_douintvec(const struct ctl_table *table, int dir, void *buffer,
* This routine will ensure the values are within the range specified by
* table->extra1 (min) and table->extra2 (max).
*
- * Returns 0 on success or -EINVAL when the range check fails and
+ * Returns: %0 on success or -EINVAL when the range check fails and
* SYSCTL_USER_TO_KERN(dir) == true
*/
int proc_dointvec_minmax(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
{
- return do_proc_dointvec(table, dir, buffer, lenp, ppos,
- do_proc_int_conv_minmax);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_INT,
+ (union proc_vec_conv){ .int_conv = do_proc_int_conv_minmax });
}
/**
@@ -904,14 +885,14 @@ int proc_dointvec_minmax(const struct ctl_table *table, int dir,
* (max). And Check that the values are less than UINT_MAX to avoid having to
* support wrap around uses from userspace.
*
- * Returns 0 on success or -ERANGE when range check failes and
+ * Returns: %0 on success or -ERANGE when range check failes and
* SYSCTL_USER_TO_KERN(dir) == true
*/
int proc_douintvec_minmax(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
{
- return do_proc_douintvec(table, dir, buffer, lenp, ppos,
- do_proc_uint_conv_minmax);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_UINT,
+ (union proc_vec_conv){ .uint_conv = do_proc_uint_conv_minmax });
}
/**
@@ -929,7 +910,7 @@ int proc_douintvec_minmax(const struct ctl_table *table, int dir,
* This routine will ensure the values are within the range specified by
* table->extra1 (min) and table->extra2 (max).
*
- * Returns 0 on success or an error on SYSCTL_USER_TO_KERN(dir) == true
+ * Returns: %0 on success or an error on SYSCTL_USER_TO_KERN(dir) == true
* and the range check fails.
*/
int proc_dou8vec_minmax(const struct ctl_table *table, int dir,
@@ -954,8 +935,8 @@ int proc_dou8vec_minmax(const struct ctl_table *table, int dir,
tmp.extra2 = (unsigned int *) &max;
val = READ_ONCE(*data);
- res = do_proc_douintvec(&tmp, dir, buffer, lenp, ppos,
- do_proc_uint_conv_minmax);
+ res = do_proc_vec(&tmp, dir, buffer, lenp, ppos, PROC_VEC_UINT,
+ (union proc_vec_conv){ .uint_conv = do_proc_uint_conv_minmax });
if (res)
return res;
if (SYSCTL_USER_TO_KERN(dir))
@@ -964,87 +945,129 @@ int proc_dou8vec_minmax(const struct ctl_table *table, int dir,
}
EXPORT_SYMBOL_GPL(proc_dou8vec_minmax);
-static int do_proc_doulongvec_minmax(const struct ctl_table *table, int dir,
- void *buffer, size_t *lenp, loff_t *ppos,
- unsigned long convmul,
- unsigned long convdiv)
+/**
+ * proc_ulong_conv - Change user or kernel pointer based on direction
+ *
+ * @u_ptr: pointer to user variable
+ * @k_ptr: pointer to kernel variable
+ * @dir: %TRUE if this is a write to the sysctl file
+ * @tbl: the sysctl table
+ * @k_ptr_range_check: Check range for k_ptr when %TRUE
+ * @user_to_kern: Callback used to assign value from user to kernel var
+ * @kern_to_user: Callback used to assign value from kernel to user var
+ *
+ * When direction is kernel to user, then the u_ptr is modified.
+ * When direction is user to kernel, then the k_ptr is modified.
+ *
+ * Returns: 0 on success
+ */
+int proc_ulong_conv(ulong *u_ptr, ulong *k_ptr, int dir,
+ const struct ctl_table *tbl, bool k_ptr_range_check,
+ int (*user_to_kern)(const ulong *u_ptr, ulong *k_ptr),
+ int (*kern_to_user)(ulong *u_ptr, const ulong *k_ptr))
{
- unsigned long *i, *min, *max;
- int vleft, first = 1, err = 0;
- size_t left;
- char *p;
-
- if (!table->data || !table->maxlen || !*lenp ||
- (*ppos && SYSCTL_KERN_TO_USER(dir))) {
- *lenp = 0;
- return 0;
- }
-
- i = table->data;
- min = table->extra1;
- max = table->extra2;
- vleft = table->maxlen / sizeof(unsigned long);
- left = *lenp;
+ if (SYSCTL_KERN_TO_USER(dir))
+ return kern_to_user(u_ptr, k_ptr);
- if (SYSCTL_USER_TO_KERN(dir)) {
- if (proc_first_pos_non_zero_ignore(ppos, table))
- goto out;
+ if (k_ptr_range_check) {
+ ulong tmp_k;
+ int ret;
- if (left > PAGE_SIZE - 1)
- left = PAGE_SIZE - 1;
- p = buffer;
- }
+ if (!tbl)
+ return -EINVAL;
+ ret = user_to_kern(u_ptr, &tmp_k);
+ if (ret)
+ return ret;
+ if ((tbl->extra1 && *(ulong *)tbl->extra1 > tmp_k) ||
+ (tbl->extra2 && *(ulong *)tbl->extra2 < tmp_k))
+ return -ERANGE;
+ WRITE_ONCE(*k_ptr, tmp_k);
+ } else
+ return user_to_kern(u_ptr, k_ptr);
+ return 0;
+}
- for (; left && vleft--; i++, first = 0) {
- unsigned long val;
+/**
+ * proc_ulong_u2k_conv_uop - Assign user value to a kernel pointer
+ *
+ * @u_ptr: pointer to user space variable
+ * @k_ptr: pointer to kernel variable
+ * @u_ptr_op: execute this function before assigning to k_ptr
+ *
+ * Uses WRITE_ONCE to assign value to k_ptr. Executes u_ptr_op if
+ * not NULL.
+ *
+ * Returns: 0 on success.
+ */
+int proc_ulong_u2k_conv_uop(const ulong *u_ptr, ulong *k_ptr,
+ ulong (*u_ptr_op)(const ulong))
+{
+ ulong u = u_ptr_op ? u_ptr_op(*u_ptr) : *u_ptr;
- if (SYSCTL_USER_TO_KERN(dir)) {
- bool neg;
+ WRITE_ONCE(*k_ptr, u);
+ return 0;
+}
- proc_skip_spaces(&p, &left);
- if (!left)
- break;
+static int proc_ulong_u2k_conv(const ulong *u_ptr, ulong *k_ptr)
+{
+ return proc_ulong_u2k_conv_uop(u_ptr, k_ptr, NULL);
+}
- err = proc_get_long(&p, &left, &val, &neg,
- proc_wspace_sep,
- sizeof(proc_wspace_sep), NULL);
- if (err || neg) {
- err = -EINVAL;
- break;
- }
+/**
+ * proc_ulong_k2u_conv_kop - Assign kernel value to a user space pointer
+ *
+ * @u_ptr: pointer to user space variable
+ * @k_ptr: pointer to kernel variable
+ * @k_ptr_op: Operation applied to k_ptr before assignment
+ *
+ * Uses READ_ONCE to assign value to u_ptr. Executes k_ptr_op if
+ * not NULL.
+ *
+ * Returns: 0 on success.
+ */
+int proc_ulong_k2u_conv_kop(ulong *u_ptr, const ulong *k_ptr,
+ ulong (*k_ptr_op)(const ulong))
+{
+ ulong val = k_ptr_op ? k_ptr_op(READ_ONCE(*k_ptr)) : READ_ONCE(*k_ptr);
+ *u_ptr = (ulong)val;
+ return 0;
+}
- val = convmul * val / convdiv;
- if ((min && val < *min) || (max && val > *max)) {
- err = -EINVAL;
- break;
- }
- WRITE_ONCE(*i, val);
- } else {
- val = convdiv * READ_ONCE(*i) / convmul;
- if (!first)
- proc_put_char(&buffer, &left, '\t');
- proc_put_long(&buffer, &left, val, false);
- }
- }
+static int proc_ulong_k2u_conv(ulong *u_ptr, const ulong *k_ptr)
+{
+ return proc_ulong_k2u_conv_kop(u_ptr, k_ptr, NULL);
+}
- if (SYSCTL_KERN_TO_USER(dir) && !first && left && !err)
- proc_put_char(&buffer, &left, '\n');
- if (SYSCTL_USER_TO_KERN(dir) && !err)
- proc_skip_spaces(&p, &left);
- if (SYSCTL_USER_TO_KERN(dir) && first)
- return err ? : -EINVAL;
- *lenp -= left;
-out:
- *ppos += *lenp;
- return err;
+static int do_proc_ulong_conv(bool *negp, ulong *u_ptr, ulong *k_ptr, int dir,
+ const struct ctl_table *tbl)
+{
+ return proc_ulong_conv(u_ptr, k_ptr, dir, tbl, true,
+ proc_ulong_u2k_conv, proc_ulong_k2u_conv);
}
-int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,
+/**
+ * proc_doulongvec_conv - read a vector of unsigned longs with a custom converter
+ *
+ * @table: the sysctl table
+ * @dir: %TRUE if this is a write to the sysctl file
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ * @ppos: file position
+ * @conv: Custom converter call back
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long
+ * values from/to the user buffer, treated as an ASCII string. Negative
+ * strings are not allowed.
+ *
+ * Returns: 0 on success
+ */
+int proc_doulongvec_conv(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos,
- unsigned long convmul, unsigned long convdiv)
+ int (*conv)(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *table))
{
- return do_proc_doulongvec_minmax(table, dir, buffer, lenp, ppos,
- convmul, convdiv);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_ULONG,
+ (union proc_vec_conv){ .ulong_conv = conv });
}
/**
@@ -1061,12 +1084,13 @@ int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,
* This routine will ensure the values are within the range specified by
* table->extra1 (min) and table->extra2 (max).
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_doulongvec_minmax(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
{
- return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos, 1l, 1l);
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_ULONG,
+ (union proc_vec_conv){ .ulong_conv = do_proc_ulong_conv });
}
/**
@@ -1076,21 +1100,22 @@ int proc_doulongvec_minmax(const struct ctl_table *table, int dir,
* @buffer: the user buffer
* @lenp: the size of the user buffer
* @ppos: file position
- * @conv: Custom converter call back
+ * @conv: Custom converter call back. Defaults to do_proc_int_conv
*
- * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer
- * values from/to the user buffer, treated as an ASCII string. Negative
- * strings are not allowed.
+ * Reads/writes up to table->maxlen/sizeof(int) integer values from/to the
+ * user buffer, treated as an ASCII string.
*
* Returns: 0 on success
*/
-
int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer,
size_t *lenp, loff_t *ppos,
int (*conv)(bool *negp, unsigned long *u_ptr, int *k_ptr,
int dir, const struct ctl_table *table))
{
- return do_proc_dointvec(table, dir, buffer, lenp, ppos, conv);
+ if (!conv)
+ conv = do_proc_int_conv;
+ return do_proc_vec(table, dir, buffer, lenp, ppos, PROC_VEC_INT,
+ (union proc_vec_conv){ .int_conv = conv });
}
/**
@@ -1108,7 +1133,7 @@ int proc_dointvec_conv(const struct ctl_table *table, int dir, void *buffer,
* large bitmaps may be represented in a compact manner. Writing into
* the file will clear the bitmap then update it with the given input.
*
- * Returns 0 on success.
+ * Returns: %0 on success.
*/
int proc_do_large_bitmap(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
@@ -1240,7 +1265,7 @@ int proc_do_large_bitmap(const struct ctl_table *table, int dir,
return err;
}
-#else /* CONFIG_PROC_SYSCTL */
+#else /* CONFIG_SYSCTL */
int proc_dostring(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
@@ -1280,7 +1305,7 @@ int proc_douintvec_minmax(const struct ctl_table *table, int dir,
int proc_douintvec_conv(const struct ctl_table *table, int write, void *buffer,
size_t *lenp, loff_t *ppos,
- int (*conv)(unsigned long *lvalp, unsigned int *valp,
+ int (*conv)(bool *negp, ulong *lvalp, uint *valp,
int write, const struct ctl_table *table))
{
return -ENOSYS;
@@ -1317,9 +1342,10 @@ int proc_doulongvec_minmax(const struct ctl_table *table, int dir,
return -ENOSYS;
}
-int proc_doulongvec_minmax_conv(const struct ctl_table *table, int dir,
+int proc_doulongvec_conv(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos,
- unsigned long convmul, unsigned long convdiv)
+ int (*conv)(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *table))
{
return -ENOSYS;
}
@@ -1338,7 +1364,7 @@ int proc_do_large_bitmap(const struct ctl_table *table, int dir,
return -ENOSYS;
}
-#endif /* CONFIG_PROC_SYSCTL */
+#endif /* CONFIG_SYSCTL */
#if defined(CONFIG_SYSCTL)
int proc_do_static_key(const struct ctl_table *table, int dir,
@@ -1372,7 +1398,7 @@ int proc_do_static_key(const struct ctl_table *table, int dir,
}
static const struct ctl_table sysctl_subsys_table[] = {
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
{
.procname = "sysctl_writes_strict",
.data = &sysctl_writes_strict,
diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
index d51428867a33..213ae1d6a014 100644
--- a/kernel/time/jiffies.c
+++ b/kernel/time/jiffies.c
@@ -98,7 +98,7 @@ void __init register_refined_jiffies(long cycles_per_second)
__clocksource_register(&refined_jiffies);
}
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
static ulong mult_hz(const ulong val)
{
return val * HZ;
@@ -185,7 +185,24 @@ static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr,
sysctl_u2k_int_conv_ms, sysctl_k2u_int_conv_ms);
}
-#else // CONFIG_PROC_SYSCTL
+static int sysctl_u2k_ulong_conv_ms(const ulong *u_ptr, ulong *k_ptr)
+{
+ return proc_ulong_u2k_conv_uop(u_ptr, k_ptr, sysctl_msecs_to_jiffies);
+}
+
+static int sysctl_k2u_ulong_conv_ms(ulong *u_ptr, const ulong *k_ptr)
+{
+ return proc_ulong_k2u_conv_kop(u_ptr, k_ptr, sysctl_jiffies_to_msecs);
+}
+
+static int do_proc_ulong_conv_ms_jiffies(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *tbl)
+{
+ return proc_ulong_conv(u_ptr, k_ptr, dir, tbl, false,
+ sysctl_u2k_ulong_conv_ms, sysctl_k2u_ulong_conv_ms);
+}
+
+#else // CONFIG_SYSCTL
static int do_proc_int_conv_jiffies(bool *negp, ulong *u_ptr, int *k_ptr,
int dir, const struct ctl_table *tbl)
{
@@ -211,6 +228,12 @@ static int do_proc_int_conv_ms_jiffies_minmax(bool *negp, ulong *u_ptr,
{
return -ENOSYS;
}
+
+static int do_proc_ulong_conv_ms_jiffies(bool *negp, ulong *u_ptr, ulong *k_ptr,
+ int dir, const struct ctl_table *tbl)
+{
+ return -ENOSYS;
+}
#endif
/**
@@ -309,8 +332,8 @@ int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int dir,
int proc_doulongvec_ms_jiffies_minmax(const struct ctl_table *table, int dir,
void *buffer, size_t *lenp, loff_t *ppos)
{
- return proc_doulongvec_minmax_conv(table, dir, buffer, lenp, ppos,
- HZ, 1000l);
+ return proc_doulongvec_conv(table, dir, buffer, lenp, ppos,
+ do_proc_ulong_conv_ms_jiffies);
}
EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
diff --git a/kernel/utsname_sysctl.c b/kernel/utsname_sysctl.c
index bfbaaecb1dd4..6c1522201e39 100644
--- a/kernel/utsname_sysctl.c
+++ b/kernel/utsname_sysctl.c
@@ -13,7 +13,7 @@
#include <linux/wait.h>
#include <linux/rwsem.h>
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
static void *get_uts(const struct ctl_table *table)
{
@@ -122,7 +122,7 @@ static const struct ctl_table uts_kern_table[] = {
},
};
-#ifdef CONFIG_PROC_SYSCTL
+#ifdef CONFIG_SYSCTL
/*
* Notify userspace about a change in a certain entry of uts_kern_table,
* identified by the parameter proc.
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 1244dcac2294..73287ef2498c 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2710,7 +2710,7 @@ config TEST_FIRMWARE
config TEST_SYSCTL
tristate "sysctl test driver"
- depends on PROC_SYSCTL
+ depends on SYSCTL
help
This builds the "test_sysctl" module. This driver enables to test the
proc sysctl interfaces available to drivers safely without affecting
diff --git a/lib/test_sysctl.c b/lib/test_sysctl.c
index c02aa9c868f2..909cfcf76dbf 100644
--- a/lib/test_sysctl.c
+++ b/lib/test_sysctl.c
@@ -7,7 +7,7 @@
/*
* This module provides an interface to the proc sysctl interfaces. This
- * driver requires CONFIG_PROC_SYSCTL. It will not normally be loaded by the
+ * driver requires CONFIG_SYSCTL. It will not normally be loaded by the
* system unless explicitly requested by name. You can also build this driver
* into your kernel.
*/
diff --git a/net/mpls/Kconfig b/net/mpls/Kconfig
index d672ab72ab12..829fb1788b1c 100644
--- a/net/mpls/Kconfig
+++ b/net/mpls/Kconfig
@@ -26,7 +26,7 @@ config NET_MPLS_GSO
config MPLS_ROUTING
tristate "MPLS: routing support"
depends on NET_IP_TUNNEL || NET_IP_TUNNEL=n
- depends on PROC_SYSCTL
+ depends on SYSCTL
help
Add support for forwarding of mpls packets.
diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config
index d83e11298b01..30d5fcb09a83 100644
--- a/tools/testing/selftests/net/config
+++ b/tools/testing/selftests/net/config
@@ -118,7 +118,7 @@ CONFIG_NFT_NAT=m
CONFIG_NUMA=y
CONFIG_OPENVSWITCH=m
CONFIG_PAGE_POOL_STATS=y
-CONFIG_PROC_SYSCTL=y
+CONFIG_SYSCTL=y
CONFIG_PSAMPLE=m
CONFIG_RPS=y
CONFIG_SYN_COOKIES=y
diff --git a/tools/testing/selftests/net/packetdrill/config b/tools/testing/selftests/net/packetdrill/config
index c4a19a785521..83dde525c53c 100644
--- a/tools/testing/selftests/net/packetdrill/config
+++ b/tools/testing/selftests/net/packetdrill/config
@@ -4,7 +4,7 @@ CONFIG_IPV6=y
CONFIG_NET_NS=y
CONFIG_NET_SCH_FIFO=y
CONFIG_NET_SCH_FQ=y
-CONFIG_PROC_SYSCTL=y
+CONFIG_SYSCTL=y
CONFIG_SYN_COOKIES=y
CONFIG_TCP_CONG_CUBIC=y
CONFIG_TCP_MD5SIG=y
diff --git a/tools/testing/selftests/wireguard/qemu/kernel.config b/tools/testing/selftests/wireguard/qemu/kernel.config
index bb89d2dfaa2a..368fd9d600c8 100644
--- a/tools/testing/selftests/wireguard/qemu/kernel.config
+++ b/tools/testing/selftests/wireguard/qemu/kernel.config
@@ -63,7 +63,7 @@ CONFIG_FILE_LOCKING=y
CONFIG_POSIX_TIMERS=y
CONFIG_DEVTMPFS=y
CONFIG_PROC_FS=y
-CONFIG_PROC_SYSCTL=y
+CONFIG_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15